【问题标题】:Javascript regex pattern match multiple strings ( AND, OR ) against single stringJavascript 正则表达式模式将多个字符串(AND、OR)与单个字符串匹配
【发布时间】:2013-02-12 00:07:16
【问题描述】:

我需要根据一个相当复杂的查询过滤一组字符串 - 在它的“原始”形式中,它看起来像这样:

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

感谢大家的帮助

【问题讨论】:

  • 你可能想试试a live RegExp testing tool
  • 在您的示例字符串中,“nano”出现在“regulatory”之后,但在您的正则表达式中,则相反。是否有任何预期的模式使得一个总是在另一个之前?再举几个例子有助于解释您的要求。
  • @Barney - 好建议,这就是我走到这一步的原因
  • @Chirag64 - 我匹配的字符串最初是推文,来自这个提要:twitter.com/nanoTOES - 所以,没有顺序,我们只是想减少数量并增加相关性.
  • @QL Studio:恐怕您将不得不在 AND & OR 中使用多个 if 条件,而不是在这种情况下尝试将所有内容都放在一个正则表达式中。

标签: javascript regex match


【解决方案1】:

单一的正则表达式不是正确的工具,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 */

【讨论】:

  • 请您解释一下 [\b] - 我读到“\b 是退格字符”,但我不确定这有什么关系?
  • @QLStudio:在普通字符串中,"\b" 确实是一个退格字符。在正则表达式中,/\b/(相当于new Regex("\\b"))是word boundary anchor。此锚点匹配字母数字单词的开头或结尾。因此/\brisk\b/ 只匹配"risk""There is a risk!",而不匹配"brisk""risky"
  • 感谢您的解释 - 我已经离开 javasript,因为 API 的 1.0 版正在关闭,但我认为正则表达式应该几乎可以像在 PHP 中一样工作 - 我会发布一个当我把一切都修好后,完整的答案。
【解决方案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”,我会按单词分隔符拆分句子并检查单个单词。

【讨论】:

  • @EP - 请参阅我上面的评论,我匹配的字符串的顺序与其内容一样随机。我只是想“过滤”大量推文基于正则表达式 - 也许这是错误的方法?
  • @QLStudio 我的建议不合适吗?
  • @EP - 是的,抱歉 - 您的解决方案解决了订单问题.. 但是我仍然可以在正常的 JS 搜索中使用通配符 ( * ) 吗?
  • 我需要匹配 nano*(例如纳米技术)和regulat*(例如法规)
  • indexOf 使用字符集而不是单词.. 所以"nanotechnology".indexOf('nano') 返回0(大于-1
猜你喜欢
  • 2014-04-10
  • 2021-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
  • 2014-10-11
相关资源
最近更新 更多