0

我正在编写一个函数,它可以有两种潜在的输入形式:

  1. This is {a {string}}
  2. This {is} a {string}

我称用大括号括起来的子字符串为“标签”。我可能在一个字符串中有任意数量的标签,并且它们可以嵌套任意深度。

我尝试编写一个正则表达式来抓取标签,这当然在嵌套标签上失败了,grabbing {a {string},缺少第二个花括号。我可以将其视为一个递归问题,但是在盯着错误答案太久之后,我觉得我看不到真正明显的东西。

我可以做些什么来将潜在的标签分成多个部分,以便可以处理和替换它们?

更复杂的版本

def parseTags( oBody, szText )


  if szText.match(/\{(.*)\}/)
    szText.scan(/\{(.*)\}/) do |outers|
      outers.each do |blah|
        if blah.match(/(.*)\}(.*)\{(.*)/)
          blah.scan(/(.*)\}(.*)\{(.*)/) do |inners|
            inners.each do |tags|
              szText = szText.sub("\{#{tags}\}", parseTags( oBody, tags ))
            end
          end
        else
          szText = szText.sub("\{#{blah}\}", parseTags( oBody, blah ))
        end
      end
    end
  end
  if szText.match(/(\w+)\.(\w+)(?:\.([A-Za-z0-9.\[\]": ]*))/)
    func = $1+"_"+$2
    begin
      szSub = self.send func, oBody, $3
    rescue Exception=>e
      szSub = "{Error: Function #{$1}_#{$2} not found}"
      $stdout.puts "DynamicIO Error Encountered: #{e}"
    end
    szText = szText.sub("#{$1}.#{$2}#{$3!=nil ? "."+$3 : ""}", szSub)
  end
  return szText
end

这是修修补补太久的结果。它不干净,但它确实适用于类似于“1”的情况 -{help.divider.red.sys.["{pc.login}"]}替换为---------------[ Duwnel ]---------------. 然而,{pc.attr.str.dotmode} {ansi.col.red}|{ansi.col.reset} {pc.attr.pre.dotmode} {ansi.col.red}|{ansi.col.reset} {pc.attr.int.dotmode}内爆非常出色,随机出现红色条纹和缺失文本的样本。

解释一下,任何标记{ansi.col.red}的东西都会标记 ansi red 代码,reset 会转义色块,并{pc.attr.XXX.dotmode}在“o”中显示 1 到 10 之间的数字。

4

2 回答 2

2

正如其他人所指出的,这是解析引擎的完美案例。正则表达式往往不能很好地处理嵌套对。

Treetop是一个很棒的 PEG 解析器,你可能有兴趣看看。主要思想是您在规则中定义要解析的所有内容(包括空格)。这些规则允许您递归地解析括号对之类的东西。

这是一个从嵌套括号对创建字符串数组的示例语法。通常语法是在一个单独的文件中定义的,但为了简单起见,我在最后包含了语法并用 Ruby 的DATA常量加载它。

require 'treetop'

Treetop.load_from_string DATA.read

parser = BracketParser.new

p parser.parse('This is {a {string}}').value

#=> ["This is ", ["a ", ["string"]]]

p parser.parse('This {is} a {string}').value

#=> ["This ", ["is"], " a ", ["string"]]

__END__
grammar Bracket
   rule string
      (brackets / not_brackets)+
      {
         def value
            elements.map{|e| e.value }
         end
      }
   end

   rule brackets
      '{' string '}'
      {
         def value
            elements[1].value
         end
      }
   end

   rule not_brackets
      [^{}]+
      {
         def value
            text_value
         end
      }
   end
end
于 2013-05-31T03:55:50.893 回答
1

我建议您不要使用更复杂的正则表达式来解决这个问题,而是查看 Ruby 的基于语法的解析引擎之一。在大多数这些中设计递归和嵌套语法是可能的。

parslet可能是您解决问题的好地方。erb-alike 示例虽然没有演示嵌套,但可能最符合您的需求:https ://github.com/kschiess/parslet/blob/master/example/erb.rb

于 2013-05-30T22:43:07.767 回答