正则表达式只返回一个匹配结果

3

我有一组关键词,任何一个关键词都可能包含空格符['one', 'one two']。我从这些关键词生成了一个正则表达式,如下:/\b(?i:one|one\ two|three)\b/。以下是完整示例:

keywords = ['one', 'one two', 'three']
re = /\b(?i:#{ Regexp.union(keywords).source })\b/
text = 'Some word one and one two other word'
text.downcase.scan(re)

这段代码的结果是:
=> ["one", "one"]

如何找到第二个关键词one two的匹配项,并获得以下结果?
=> ["one", "one two"]

1
将交替项的顺序从最长到最短进行更改。 - revo
3个回答

4
重点在于\bone\bone two中匹配one,因为这个分支出现在one two之前,所以它“获胜”(参见记住正则表达式引擎是贪婪的)。
在构建正则表达式之前,您需要按降序排序关键字数组。 此时它应该是这样的:
(?-mix:\b(?i:three|one\ two|one)\b)

这样,长度更长的one two会在长度较短的one之前进行匹配。请参见Ruby演示
keywords = ['one', 'one two', 'three']
keywords = keywords.dup.sort.reverse
re = /\b(?i:#{ Regexp.union(keywords).source })\b/
text = 'Some word one and one two other word'
puts text.downcase.scan(re)
# => [ one, one two ]

1
请注意,这是因为无论“B”是什么,“AB”>“A”。[如果字符串长度不同,并且在比较到最短长度时字符串相等,则较长的字符串被认为大于较短的字符串。](https://ruby-doc.org/core-2.4.0/String.html#method-i-3C-3D-3E) - Schwern

4
Regex 是渴望匹配的。一旦它们找到一个匹配项,它们就不会尝试找到另一个可能更长的匹配项(有一个重要的例外)。 /\b(?i:one|one\ two|three)\b/ 永远不会匹配 one two,因为它总是先匹配 one。你需要 /\b(?i:one two|one|three)\b/,这样它就会首先尝试匹配 one two。可能最简单的自动化方法是按最长的关键字排序。
keywords = ['one', 'one two', 'three']
re = Regexp.union(keywords.sort { |a,b| b.length <=> a.length }).source
re = /\b#{re}\b/i;
text = 'Some word one and one two other word'
puts text.scan(re)

请注意,我将整个正则表达式设置为不区分大小写,这比使用(?:...)更易于阅读,而且字符串转为小写是多余的。

例外情况是重复,例如+*等。它们默认是贪婪的。 .+会匹配尽可能多的字符。这是贪婪的。您可以使用?使其变成懒惰模式,以匹配它看到的第一件事。 .+?将匹配单个字符。

"A foot of fools".match(/(.*foo)/);  # matches "A foot of foo"
"A foot of fools".match(/(.*?foo)/);  # matches "A foo"

0

我尝试了您的示例,将数组的第一个元素移动到第二个位置,并且它可以正常工作(例如http://rubular.com/r/4F2Hc46wHT)。

实际上,看起来第一个关键字“重叠”了第二个关键字。

如果您无法更改关键字顺序,则此响应可能没有帮助。


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