JavaScript正则表达式模式匹配单个字符串中的多个字符串(AND,OR)

6

我需要根据一个相当复杂的查询来过滤字符串集合,它的“原始”形式如下:

nano* AND (regulat* OR *toxic* OR ((risk OR hazard) AND (exposure OR release)) )

以下是需要匹配的字符串示例:

Workshop on the Second Regulatory Review on Nanomaterials, 30 January 2013, Brussels

所以,我需要使用AND OR和通配符进行匹配 - 所以,我想我需要在JavaScript中使用正则表达式。

我已经正确地循环、过滤和一般工作,但我100%确定我的正则表达式是错误的 - 有些结果被错误地省略了 - 在这里:

/(nano[a-zA-Z])?(regulat[a-zA-Z]|[a-zA-Z]toxic[a-zA-Z]|((risk|hazard)*(exposure|release)))/i

非常感谢您的帮助 - 我无法正确抽象我的思维以理解这个语法!

更新:

有些人指出正则表达式构建的顺序的重要性,但是我无法控制将被搜索的文本字符串的顺序,因此我需要找到一个可以在任何顺序下工作的解决方案。

更新:

最终使用了PHP解决方案,由于Twitter API 1.0已经被弃用,请参见pastebin中的示例函数(我知道在这里粘贴代码更好,但是有很多...):

function: http://pastebin.com/MpWSGtHK usage: http://pastebin.com/pP2AHEvk

感谢所有的帮助。


你可能想尝试使用在线正则表达式测试工具 - Barney
@Chirag64 - 我要匹配的字符串最初是来自这个推特源的推文:https://twitter.com/nanoTOES - 因此,没有顺序,我们只是试图减少数量并增加相关性。 - Q Studio
@QL Studio:恐怕您必须使用多个AND和OR条件,而不是试图将所有内容都放入单个正则表达式中。 - Chirag Bhatia - chirag64
可以使用一个正则表达式来完成这个任务,但我建议不要这样做,因为在JavaScript中甚至不能使用注释/详细的正则表达式,并且该正则表达式将几乎无法阅读(即使比大多数正则表达式更难以阅读)。 - Tim Pietzcker
@TimPietzcker - 很好的观点,正则表达式对我来说有些神秘 - 但是通配符搜索怎么办 - 我能用标准搜索实现这个吗,还是需要将正则表达式拆分成单个部分并逐个传递..听起来有点像hack job..但这不会是第一次 :) - Q Studio
显示剩余2条评论
2个回答

24

在我看来,单个正则表达式不是解决这个问题的正确工具:

/^(?=.*\bnano)(?=(?:.*\bregulat|.*toxic|(?=.*(?:\brisk\b|\bhazard\b))(?=.*(?:\bexposure\b|\brelease\b))))/i.test(subject))

如果字符串符合您设定的条件,would会返回True,但我觉得嵌套的前瞻很难理解。如果JavaScript支持注释的正则表达式,它会像这样:
^                 # Anchor search to start of string
(?=.*\bnano)      # Assert that the string contains a word that starts with nano
(?=               # AND assert that the string contains...
 (?:              #  either
  .*\bregulat     #   a word starting with regulat
 |                #  OR
  .*toxic         #   any word containing toxic
 |                #  OR
  (?=             #   assert that the string contains
   .*             #    any string
   (?:            #    followed by
    \brisk\b      #    the word risk
   |              #    OR
    \bhazard\b    #    the word hazard
   )              #    (end of inner OR alternation)
  )               #   (end of first AND condition)
  (?=             #   AND assert that the string contains
   .*             #    any string
   (?:            #    followed by
    \bexposure\b  #    the word exposure
   |              #    OR
    \brelease\b   #    the word release
   )              #    (end of inner OR alternation)
  )               #   (end of second AND condition)
 )                #  (end of outer OR alternation)
)                 # (end of lookahead assertion)

请注意,整个正则表达式由前瞻断言组成,因此匹配结果本身始终为空字符串。
相反,您可以使用单个正则表达式:
if (/\bnano/i.test(str) &&
    ( 
        /\bregulat|toxic/i.test(str) ||
        ( 
            /\b(?:risk|hazard)\b/i.test(str) &&
            /\b(?:exposure|release)\b/i.test(str)
        )
    )
)    /* all tests pass */

请问能否解释一下 [\b] - 我看到过 "\b 是一个退格字符",但我不确定它与代码有什么关系? - Q Studio
@QLStudio:在普通字符串中,"\b"确实是一个退格字符。但在正则表达式中,/\b/(等同于new Regex("\\b"))是一个单词边界锚点。该锚点匹配字母数字单词的开头或结尾。因此,/\brisk\b/只匹配"risk""There is a risk!",而不匹配"brisk""risky" - Tim Pietzcker
感谢您的解释 - 我已经放弃了JavaScript,因为API的1.0版本即将关闭,但是正则表达式在PHP中应该几乎可以直接使用 - 当我把所有问题都解决好后,我会发布完整的答案。 - Q Studio

2

正则表达式必须按顺序在字符串中移动。在模式中,“nano”出现在“regulat”之前,但在测试字符串中它们被交换了。不要使用正则表达式来处理此类情况,最好使用普通的字符串解析:

if (str.indexOf('nano') > -1) {
    if (str.indexOf('regulat') > -1 || str.indexOf('toxic') > -1
        || ((str.indexOf('risk') > - 1 || str.indexOf('hazard') > -1)
        && (str.indexOf('exposure') > -1 || str.indexOf('release') > -1)
    )) {
        /* all tests pass */
    }
}

如果你想实际捕获单词(例如从“regulat”中获取“Regulatory”),我会通过单词之间的分隔符来拆分句子并检查每个单词。

1
@EP - 请看我上面的评论,我要匹配的字符串顺序与内容一样随机。我只是试图基于正则表达式在大量推文集合中进行“过滤” - 或许这种方法不正确? - Q Studio
@QLStudio对此是否不恰当? - Explosion Pills
@EP - 是的,抱歉 - 您的解决方案解决了顺序问题...但是我仍然可以在普通JS搜索中使用通配符(*)字符吗? - Q Studio
indexOf 适用于字符集而不是单词.. 所以 "nanotechnology".indexOf('nano') 返回 0(大于 -1)。 - Explosion Pills
@EP - 好的,所以..我已经添加了这个并且它正在工作 - 很高兴能够远离正则表达式..我会进行更多测试并稍后接受 - 谢谢! - Q Studio
显示剩余2条评论

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