我有这个正则表达式:
regex = %r{\A(?<foo> a\g<foo>a | b\g<foo>b | c)\Z}x
当我针对几个字符串测试它时,它看起来像无上下文语法一样强大,因为它正确处理递归。
regex.match("aaacaaa")
# => #<MatchData "aaacaaa" foo:"aaacaaa">
regex.match("aacaa")
# => #<MatchData "aacaa" foo:"aacaa">
regex.match("aabcbaa")
# => #<MatchData "aabcbaa" foo:"aabcbaa">
regex.match("aaacaa")
# => nil
“Fun with Ruby 1.9 Regular Expressions”有一个例子,他实际上安排了一个正则表达式的所有部分,使它看起来像一个无上下文的语法,如下所示:
sentence = %r{
(?<subject> cat | dog | gerbil ){0}
(?<verb> eats | drinks| generates ){0}
(?<object> water | bones | PDFs ){0}
(?<adjective> big | small | smelly ){0}
(?<opt_adj> (\g<adjective>\s)? ){0}
The\s\g<opt_adj>\g<subject>\s\g<verb>\s\g<opt_adj>\g<object>
}x
在重新排列正则表达式部分的技术和递归命名捕获组的示例之间,这是否意味着Ruby 1.9正则表达式具有与无上下文语法等效的功能?
答案 0 :(得分:7)
这是关于Ruby 1.9中使用的Oniguruma regexp引擎的一个很棒的东西 - 它具有解析器的强大功能,并且不限于识别常规语言。它具有正面和负面的前瞻/外观,甚至可用于识别某些不无上下文的语言!以下面的例子为例:
regexp = /\A(?<AB>a\g<AB>b|){0}(?=\g<AB>c)a*(?<BC>b\g<BC>c|){1}\Z/
此正则表达式识别“abc”,“aabbcc”,“aaabbbccc”等字符串 - “a”,“b”和“c”的数量必须相等,否则它们将不匹配。< / p>
(一个限制:你不能在前瞻和后方使用命名组。)
虽然我没有偷看,但Oniguruma似乎通过简单的递归下降处理命名组,当事情不匹配时备份。我观察到它不能处理左递归。例如:
irb(main):013:0> regexp = /(?<A>\g<A>a|)/
SyntaxError: (irb):13: never ending recursion: /(?<A>\g<A>a|)/
from C:/Ruby192/bin/irb:12:in `<main>'
我不太清楚地记得我的解析理论,但我认为像这样的非确定性自上而下的解析器应该能够解析任何无上下文的语言。 (“语言”,而不是“语法”;如果您的语法已经离开递归,则必须将其转换为正确的递归。)如果这不正确,请编辑此帖子。