StringScanner匹配一个字符串,好像它是一个位置

时间:2016-04-13 02:46:48

标签: ruby regex tokenize

我尝试使用StringScanner将字符串解析为令牌以便以后处理。一切顺利,直到我测试了正则表达式语法解析。 Regexen看起来像这样:

r|hello|gmi
r:there|there:gmi
r/:(?=[jedi])[sith]:/gmi
r!hello!gmi

r,然后是|(或其他几个字符,但现在不相关),其次是正则表达式的正文 - 可以包括已转义的字符,例如\|\\ - 然后是另一个|,然后是正则表达式的标记。

要查找正则表达式文字,我使用的代码看起来非常像这样:

require 'strscan'
scanner = StringScanner.new('r|abc|  ')

puts "pre-regex: #{scanner.inspect}"
puts "got a char: #{scanner.getch} (res: #{scanner.inspect})"
divider = scanner.getch
puts "got divider: #{divider.inspect}"
puts "mid-regex: #{scanner.inspect}"
# this bit still fails even if you replace `#{divider}' with `|'
res = scanner.scan_until(/(?<![^\\]\\)#{divider}[a-z]*/)
puts "post-regex: #{scanner.inspect}"

if scanner.skip(/\s+/)# || scanner.skip(/;-.*?-;/m)
  puts "Success! #{res}"
else
  puts "Fail. Ended at: #{scanner.inspect}"
  puts "(res was #{res.inspect})"
end

Try it online at ideone

在这里,我已经尽可能地减少它,以便我能够清楚地显示问题。在实际代码中,它是大量代码的一部分,其中绝大多数代码都不相关。我已经将这个漏洞缩小到了这一部分 - 您可以使用该链接查看它是否存在 - 但我无法弄清楚为什么这不能正确扫描到下一个|实例,然后返回标志。

作为旁注,如果有更好的方法,请告诉我。我发现我非常喜欢StringScanner,但那可能是因为我对regexen很着迷,以至于我称之为regexen。

TL; DR :为什么StringScanner显然匹配,就好像它的位置是一个字符一样,我怎样才能让它正常工作?

1 个答案:

答案 0 :(得分:1)

问题是Ruby使用字符串按原样插入正则表达式文字,例如

divider = '|'
/(?<![^\\]\\)#{divider}[a-z]*/
=> /(?<![^\\]\\)|[a-z]*/

要逃避分隔符,您可以

divider = '|'
/(?<![^\\]\\)#{Regexp.quote divider}[a-z]*/
=> /(?<![^\\]\\)\|[a-z]*/

此修改使代码通过,但您仍需要验证分隔符是否为非单词字符。