为什么正则表达式中的插值数组返回一个位置而不是nil?

时间:2017-03-22 20:10:00

标签: arrays ruby regex interpolation

这是我尝试过的事情

lorem = 'Lorem ipsum dolor sit amet, co'
# => "Lorem ipsum dolor sit amet, co"
oops  = ['oops']
# => ["oops"]

这是我得到的:

lorem =~ /#{oops}/
# => 1

我原本预期是零或例外。

显然它正在将字符串数组中的第一项用于oops并匹配。 '○'是Lorem ipsum中的第二个角色......'

我在Windows 7中使用Ruby 2.3.3。

2 个答案:

答案 0 :(得分:1)

可以在正则表达式中嵌入数组,但是不能直接使用插值。如您所知,直接插值会产生character class,它将匹配元素中的所有字符以及双引号和逗号。

改为使用:

ary = ['a']
regex = Regexp.union(ary) # => /a/
/#{regex.source}/ # => /a/

ary = ['a', 'b']
regex = Regexp.union(ary) # => /a|b/
/#{regex.source}/ # => /a|b/

您可以在文档中详细了解Regexp.unionsource

但是等等!还有更多!

通常,您希望对该子表达式进行分组,以避免突然生成子字符串false-positive hits:

/foo#{regex.source}/ # => /fooa|b/

因为正则表达式引擎贪婪,所以会匹配fooab

'fooa'[/foo#{regex.source}/] # => "fooa"
'foob'[/foo#{regex.source}/] # => "b"

相反,这会有所帮助:

/foo(?:#{regex.source})/ # => /foo(?:a|b)/

'fooa'[/foo(?:#{regex.source})/] # => "fooa"
'foob'[/foo(?:#{regex.source})/] # => "foob"

但还有更多!

嵌入式正则表达式维护自己的options集合,这些集合在插值时会被保留,如果您不注意,将导致难以调试的问题:

regex = Regexp.union(ary) # => /a|b/
/#{regex}/ # => /(?-mix:a|b)/

来自文档:

  

imx也可以使用(?开关)构造在子表达式级别上应用,这将启用选项< em> on ,并为括号括起的表达式禁用选项 off

如果外部模式使用不同的选项,例如,对于不区分大小写的匹配,则可能发生以下情况:

regex = /FOO/
'foo'[/#{regex}/i] # => nil

您认为外部表达式上的i选项可以解决问题,但这里发生了什么:

/#{regex}/i # => /(?-mix:FOO)/i

简单的解决方法是使用上面示例中的source方法,该方法返回表达式的文本,但不返回选项的设置:

/#{regex.source}/i # => /FOO/i
'foo'[/#{regex.source}/i] # => "foo"

使用source并不总是正确的做法,但在您确定有意使用 的嵌入式表达式的情况下,它会有很大的帮助。不同的选项集。如果你确实达到了这一点,请务必在那时对代码进行评论,这样你的未来或继承代码的任何人都将了解正在发生的事情。否则,可能需要数天才能弄清楚发生了什么。

答案 1 :(得分:0)

我想我找到了它:

irb(main):008:0> /#{oops}/
=> /["oops"]/

正则表达式评估一个模式,该模式将查找括号中的一个字符并匹配它遇到的第一个字符,即&#39; o&#39;在Lorem ipsum的第二个位置。 。 。&#39;

我找到了吗?