首页  >  问答  >  正文

如何使这个正则表达式简化?

我有这个正则表达式:

"(WORD1.*WORD2.*WORD3)|(WORD1.*WORD3.*WORD2)|(WORD2.*WORD1.*WORD3)|(WORD2.*WORD3.*WORD1)|(WORD3.*WORD1.*WORD2)|(WORD3.*WORD2.*WORD1)"

它与这些词匹配:

WORD1WORD2WORD3
WORD1AWORD2BWORD3C
WORD3WORD1WORD2
WORD1WORD2WORD3WORD1

但不是这些话:

WORD1WORD1WORD2
WORD1AWORD1BWORD2C

当该正则表达式找到包含任意顺序的 3 个单词(WORD1WORD2WORD3)的字符串时,它就会匹配。

我想用更多的单词做同样的事情,但问题是正则表达式的大小随着单词的数量呈指数增长。 是否可以简化此正则表达式的构造方式来解决此问题(大小不会呈指数增长)?

P粉710454910P粉710454910235 天前353

全部回复(2)我来回复

  • P粉663883862

    P粉6638838622024-02-27 16:51:16

    简单地迭代所有字符串并过滤掉所有不包含所有关键字的字符串:

    (可以在下面的代码片段中找到更简洁的版本)

    function findMatch(strings, keywords) {
      const result = [];
      
      for (const string of strings) {
        if (keywords.every(keyword => string.includes(keyword))) {
          result.push(string);
        }
      }
      
      return result;
    }
    

    尝试一下:

    console.config({ maximize: true });
    
    function findMatch(strings, keywords) {
      return strings.filter(
        string => keywords.every(keyword => string.includes(keyword))
      );
    }
    
    const testcases = [
      'WORD1WORD2WORD3',
      'WORD1AWORD2BWORD3C',
      'WORD3WORD1WORD2',
      'WORD1WORD2WORD3WORD1',
      'WORD1WORD1WORD2',
      'WORD1AWORD1BWORD2C'
    ];
    
    const keywords = [
      'WORD1', 'WORD2', 'WORD3'
    ];
    
    console.log(findMatch(testcases, keywords));
    sssccc

    回复
    0
  • P粉998100648

    P粉9981006482024-02-27 11:50:29

    您可以对每个单词使用正向前瞻。

    /(?=.*WORD1)(?=.*WORD2)(?=.*WORD3).*/

    下面的更高性能版本指定起始锚点,并且在验证前瞻后仅匹配单个字符。根据OP的要求,此技术仅适用于matching,而不适用于extraction

    /^(?=.*WORD1)(?=.*WORD2)(?=.*WORD3)./

    正向先行就像一个门,只有当括号内指定的匹配存在时,它才会继续,但它不会消耗或捕获它匹配的内容——它总是零长度。如果您“向前看”以查看每个单词前面是否存在 .*,那么这些单词的顺序并不重要。如果每个单词为真,则继续进行,而不会使用任何内容进行匹配。

    如果您只关心内容是否匹配,那么两个表达式之间唯一的实质性区别就是它们花费的时间。假设您的内容中只有 3 个必需单词中的 2 个。除非解释表达式的软件能够识别尝试是徒劳的,否则它可能会在第一个位置查找三个单词“失败”,然后在第二个位置尝试“失败”,等等,直到到达最后一个位置才放弃。通过指定^,只会在第一个位置进行检查,节省了其他不必要检查的时间。当您只是寻找内容中是否存在所有单词的真/假答案时,从末尾删除 * 可以防止一些不必要的捕获。

    回复
    0
  • 取消回复