【问题标题】:Match multiple words anywhere in string匹配字符串中任意位置的多个单词
【发布时间】:2018-05-10 13:22:50
【问题描述】:

我想检查字符串selection 中的所有单词是否存在于另一个字符串中。会有任意数量的单词。这不是 OR。所有单词必须出现在匹配器中。顺序无所谓。例如,当selection"John Zeni" 时,它必须匹配" John Paul Zeni",因为"John""Zeni" 都在匹配器中。如果selection 只是"John",那么它应该匹配,但是由于有多个单词,所以所有单词都必须匹配。需要正则表达式解决方案。

这是我尝试过的:

selection = "John Zeni"
pattern = selection.split(" ").join("|")
# => "John|Zeni"
/#{Regexp.quote(pattern)}/
# => /John\|Zeni/ 
" John Paul Zeni".match(/#{Regexp.quote(pattern)}/)
# => nil 

为什么不匹配?我认为问题出在Regexp.quote。两个词在匹配器中匹配很重要。这也不应该匹配:

" John Paul Zeni" =~ /(John|Zach)/ 
# => 1

【问题讨论】:

  • 单独检查所有名称部分:selection.split(" ").all?{|name| str.include?(name)}
  • @SergioTulentsev 我需要一个正则表达式解决方案,因为最终我必须把它放在一个需要正则表达式的 Mongoid 查询中。
  • 使用前瞻:^(?=.*John)(?=.*Zeni)
  • 为什么使用Regexp.quote?你有特殊的字符需要说明吗?
  • “需要正则表达式。” - 不必要。即使在 mongodb 中,您也可以将单个子句与 $and

标签: ruby regex


【解决方案1】:
("John Zeni".split - "John Paul Zeni".split).empty?
  #=> true

如果str 可能包含标点符号,我们应该在拆分之前删除这些字符。

("John Zeni Lola".split - "John Lola Paul, Zeni.".gsub(/[[:punct:]]/,'').split).empty?
  #=> true

【讨论】:

  • 你认为 OP 不想在 John Paul,Zeni 上找到匹配项吗?
  • @revo,如果字符串可能包含标点符号,我建议将这些字符作为预处理步骤删除 (str.gsub(/[[:punct:]]/, ''))。人们可能还想对所有内容进行小写或大写。如果改为使用可能没有必要的正则表达式,但这样做会简化正则表达式。
  • 您可能希望对其进行概括,以便它适用于任意单词分隔符。
  • 问题的最后一句(“需要正则表达式解决方案。”)是在我发布答案后添加的。
  • 是的,但前两句话从未改变。
【解决方案2】:

使用正向预测来模拟AND

string = "Paul Zach"
re = '^(?=.*' + string.split(/\s+/).map{ |x| Regexp.quote(x) }.join(')(?=.*') + ')'
"John Paul Mak Zach Jack Zen" =~ /#{re}/

如果需要通过多行匹配,请启用m 标志或使用[\s\S] 而不是.。您可以在单词周围使用\b 标记确保单词不在其他单词中。

注意:顺序无关紧要。

【讨论】:

  • 您可能希望对其进行概括,使其适用于字符串中必须包含的任意数量的单词。
  • 谢谢。因为我不会 Ruby,所以我可能会不理会代码部分。
  • 是的@CarySwoveland 是对的。会有任意数量的单词。它不会总是两个。这就是我尝试合并 Regexp.quote 的原因。
  • @Donato 如果您不确定单词,我使用map 为每个单词申请Regexp.quote
  • 您需要分词,以便string 中的"Paul" 与测试字符串中的"Paula" 不匹配。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-15
  • 2016-02-23
  • 2014-03-04
  • 1970-01-01
  • 1970-01-01
  • 2015-04-08
相关资源
最近更新 更多