如何匹配另一个字符串开头的数组中的字符串

时间:2017-05-31 23:36:53

标签: arrays ruby regex string

我希望不区分大小写匹配我的数组中的字符串TOKENS,在另一个字符串的开头跟一个空格或行的结尾。

我的令牌数组看起来像:

2.4.0 :013 > TOKENS = ["m", "o"]
 => ["m", "o"]

当我尝试匹配数组中的每个元素时,它会找出错误的结果:

2.4.0 :009 > data_col = ["M", "b", "Mabc", "abc m b"]
 => ["M", "b", "Mabc", "abc m b"]
...
2.4.0 :015 > data_col.select{|string| string =~ /^[#{Regexp.union(TOKENS)}]([[:space:]]|$)/i }
 => ["M", "b"]

这匹配“M”和“b”条目,即使“b”没有出现在我的TOKENS列表中。如何修改我的正则表达式,以便只匹配正确的值“M”?

我正在使用Ruby 2.4。

1 个答案:

答案 0 :(得分:3)

我会用:

TOKENS = ["m", "o"]
DATA_COL = ["M", "b", "Mabc", "abc m b"]
RE = /^(?:#{Regexp.union(TOKENS).source})(?: |$)/i

DATA_COL.select{ |string| string[RE] }
# => ["M"]

稍微分解一下:

Regexp.union(TOKENS).source # => "m|o"
/^(?:#{Regexp.union(TOKENS).source})(?: |$)/i # => /^(?:m|o)(?: |$)/i

/^[#{Regexp.union(TOKENS)}]([[:space:]]|$)/i在循环中不是一个好主意。每次通过你强迫Ruby创建模式;效率在循环内部很重要,尤其是大循环,因此在循环外创建模式然后引用内部模式。

下一个问题是Regexp.union有一个应该匹配的正确案例的概念:

Regexp.union(TOKENS).to_s        # => "(?-mix:m|o)"

(?-mix:部分是正则表达式引擎如何记住模式的标志。当图案嵌入另一个图案时,他们会继续知道他们应该寻找什么,导致我们咬牙切齿并哭泣:

/#{Regexp.union(TOKENS)}/i # => /(?-mix:m|o)/i

尾随i告诉它应该忽略大小写的模式,但嵌入的i没有设置,所以它是尊重案例。这就是破坏你的模式的原因。

修复是在嵌入时使用source,就像我上面那样。

有关详细信息,请参阅正则表达式“options”部分。