开发者

Ruby: nested regular expressions and string replace

开发者 https://www.devze.com 2023-01-21 00:47 出处:网络
I\'m using CodeRay for syntax highlighting, but I\'m having trouble with this regular expression. The text will look like this:

I'm using CodeRay for syntax highlighting, but I'm having trouble with this regular expression. The text will look like this:

<pre><code>:::ruby
def say_hello
  puts 'hello!'
end
</code></pre>

This part: :::ruby will tell CodeRay which language the code block should be interpreted as (but it needs to be optional). So here's what I have so far:

def coderay(text)
  text.gsub(/\<pre开发者_开发知识库\>\<code\>(.+?)\<\/code\>\<\/pre\>/m) do
    CodeRay.scan($2, $3).div()
  end
end

$2 contains the code that I'm formatting (including the line that says which language to format it in), but I need to extract that first line so I can pass it as the second parameter to scan() or pass it a default parameter if that language line wasn't found. How can I do this?


In Ruby 1.9, using named groups:

default_lang=:ruby

def coderay(text)
  text.gsub(%r!<pre><code>(?::{3}(?<lang>\w+)\s+)?(?<code>.+?)</code></pre>!m) do
    if $~[:lang].nil?
      lang=default_lang
    else
      lang = $~[:lang].intern
    end
    CodeRay.scan($~[:code], lang).div()
  end
end

default_lang could also be a class or object variable rather than a local, depending on the context of coderay.

Same, but using an inline expression to handle the optional language:

default_lang=:ruby

def coderay(text)
  text.gsub(%r!<pre><code>(?::{3}(?<lang>\w+)\s+)?(?<code>.+?)</code></pre>!m) do
    CodeRay.scan($~[:code], $~[:lang].nil? ? default_lang : $~[:lang].intern).div()
  end
end

The second option is a little messier, hence you might want to avoid it.

It turns out named groups in a non-matching optional group are still counted in Ruby, so handling unmatched numbered groups isn't any different from unmatched named groups, unlike what I first thought. You can thus replace the named group references with positional references in the above and it should work the same.

default_lang=:ruby

def coderay(text)
  text.gsub(%r!<pre><code>(?::{3}(?<lang>\w+)\s+)?(?<code>.+?)</code></pre>!m) do
    CodeRay.scan($2, $1.nil? ? default_lang : $1.intern).div()
  end
end

def coderay(text)
  text.gsub(%r!<pre><code>(?::{3}(?<lang>\w+)\s+)?(?<code>.+?)</code></pre>!m) do
    if $1.nil?
      lang=default_lang
    else
      lang = $1.intern
    end
    CodeRay.scan($2, lang).div()
  end
end
0

精彩评论

暂无评论...
验证码 换一张
取 消