Ruby递归正则表达式

6

那么为什么这个不起作用呢?我正在创建一个正则表达式,它将匹配一个公式(然后成为更大标准描述的一部分)。但是我在这里卡住了,因为它似乎无法匹配嵌入到公式中的公式。

stat        = /(Stat3|Stat2|Stat1)/

number_sym  = /[0-9]*/
formula_sym = /((target's )?#{stat}|#{number_sym}|N#{number_sym})\%?/
math_sym    = /(\+|\-|\*|\/|\%)/

formula     = /^\((#{formula}|#{formula_sym})( #{math_sym} (#{formula}|#{formula_sym}))?\)$/

p "(target's Stat2 * N1%)".match(formula).to_s #matches
p "((target's Stat2 * N1%) + 3)".match(formula).to_s #no match
p "(Stat1 + ((target's Stat2 * N1%) + 3))".match(formula).to_s #no match
3个回答

7
当您使用#{ }语法时,Ruby会使用to_s将Regexp对象转换为字符串。当您将Regexp对象转换为字符串时,会发生以下情况:
irb> re = /blah/
  => /blah/
irb> re.to_s
  => "(?-mix:blah)"
irb> "my regex: #{re}"
  => "my regex: (?-mix:blah)"
irb> /my regex: #{re}/
  => /my regex: (?-mix:blah)/

为了获取您想要的字符串(在我的示例中为“blah”),请使用Regexp#source方法:
irb> re.source
"blah"

因此,以您的例子为例:

formula_sym = /((target's )?#{stat.source}|#{number_sym.source}|N#{number_sym.source})\%?/

谢谢...我确实发现为什么它没工作...我猜我应该把我的问题表述为“我怎么才能让它工作”....看起来#{formula.source}显示这个公式仍然是nil。 - Reed Debaets

4
/(
  (?<non_grouping_char>
    [^\(\{\[\<\)\}\]\>]
  ){0}
  (?<parens_group>
    \( \g<content> \)
  ){0}
  (?<brackets_group>
    \[ \g<content> \]
  ){0}
  (?<chevrons_group>
    \< \g<content> \>
  ){0}
  (?<braces_group>
    \{ \g<content> \}
  ){0}
  (?<balanced_group>
    (?>
      \g<parens_group>   |
      \g<brackets_group> |
      \g<chevrons_group> |
      \g<braces_group>
    )
  ){0}
  (?<content>
    (?> \g<balanced_group> | \g<non_grouping_char> )*
  ){0}
  \A \g<content> \Z
)/uix

如果这对您有所帮助,请给我一杯啤酒。此方法适用于任何允许命名组的正则表达式引擎。它将验证任何没有分组或嵌套字符组的内容,无论其深度如何。


1
如果我们见面了,我一定请你喝啤酒。你最喜欢的口味是什么?:) 从那时起,我投赞成票! - Stephan

1
你不能像那样使用递归:在你定义的formula中,#{formula}被转换为空字符串。你想要的超出了正则表达式的能力——正则表达式甚至无法匹配嵌套的括号。我怀疑你需要一个实际的解析器来完成你想要的功能。例如,可以查看treetop

非常棒!Treetop将使我能够轻松地将我的当前定义规范迁移到其中。谢谢! - Reed Debaets

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接