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 示例函数(我知道在这里粘贴代码更好,但是有很多......):

功能:http://pastebin.com/MpWSGtHK 用法: http: //pastebin.com/pP2AHEvk

感谢所有帮助

4

2 回答 2

24

IMO,单个正则表达式不是正确的工具:

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

如果字符串满足您提出的标准,将返回 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 */
于 2013-02-26T15:24:54.280 回答
2

正则表达式必须按顺序在字符串中移动。您在模式中的“regulat”之前有“nano”,但它们在测试字符串中被交换。我不会使用正则表达式来执行此操作,而是坚持使用普通的旧字符串解析:

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”,我会按单词分隔符拆分句子并检查单个单词。

于 2013-02-26T14:06:16.850 回答