用于匹配顺序无关紧要的相邻单词的正则表达式

时间:2018-05-30 15:19:35

标签: python regex

我正在使用正则表达式与python并试图找出匹配模式的最佳方法,其中我正在搜索的两个单词的顺序无关紧要,但它们必须相邻。例如,我正在搜索短语"fat cat lasagna co""cat fat lasagna co",我不得不想象有一种比r"\b(fat cat|cat fat) lasagna co\b"更好的方法

我读过this question,它解决了类似的问题,但这些词语不必相邻,也无法弄清楚如何将其应用于我的问题。

1 个答案:

答案 0 :(得分:1)

没有严格的更好的解决方案,但还有另一种选择。

现在,如果您有两个正常的词,如“胖”和“猫”,那么(fat cat|cat fat)无疑是最佳解决方案。但如果你有5个单词怎么办?或者,如果您的模式比fatcat更复杂,那么您不想输入两次?

代替fatcat,您有3个正则表达式ABC,而不是{{1}之间的空格}和fat你有正则表达式模式cat。在这种情况下,您可以使用此配方:

S

如果您没有(?:(?:(?!\1)()|\1(?:S))(?:(?!\2)()(?:A)|(?!\3)()(?:B)|(?!\4)()(?:C))){3} ,可以将其简化为

S

(注意:如果(?:(?!\1)()(?:A)|(?!\2)()(?:B)|(?!\3)()(?:C)){3} 不包含替换(?:X),则X可简化为X。)

实施例

如果我们设置| = Afat = Bcat =空格,我们会得到:

S

Try it online.

说明

本质上,我们使用捕获组来“记住”哪些模式已经匹配。为此,我们在这里使用这个小模式:

(?:(?:(?!\1)()|\1 )(?:(?!\2)()fat|(?!\3)()cat)){2}

这是做什么的?这是一个恰好匹配一次的正则表达式。一旦匹配,它将永远不会再匹配。如果您尝试围绕该模式添加量词,例如(?!\1)()some_pattern ,那么它将匹配一次或根本不匹配。

在该组甚至已定义之前,有一个backreference用于捕获组的技巧。由于捕获组初始化为“无法匹配”状态,negative lookahead (?:(?!\1)()some_pattern)*将成功匹配 - 但仅限第一次。因为之后,捕获组(?!\1)匹配并捕获空字符串。从现在开始,否定前瞻()将再也不会匹配。

将此作为构建基块,我们可以创建一个匹配(?!\1)fatcat的正则表达式,同时只包含单词catfatfat一次:

cat

由于负前瞻,每个单词最多只能匹配一次。在末尾添加(?:(?!\1)()fat|(?!\2)()cat){2} 量词可确保两个单词中的每一个与完全匹配一次,或者整个匹配失败。

现在我们只需找到一种方法来匹配{2}fat之间的空格。嗯,这只是同一模式的一个小变化:

cat

此模式将匹配第一个匹配项中的空字符串,并且在每个后续匹配项中它将匹配一个空格。

把它们放在一起,然后瞧瞧:

(?:(?!\1)()|\1 )

模板(懒惰)

2种模式(?:(?:(?!\1)()|\1 )(?:(?!\2)()fat|(?!\3)()cat)){2} A,带有分隔符B

S

3个模式(?:(?:(?!\1)()|\1(?:S))(?:(?!\2)()(?:A)|(?!\3)()(?:B))){2} AB,带有分隔符C

S

4个模式(?:(?:(?!\1)()|\1(?:S))(?:(?!\2)()(?:A)|(?!\3)()(?:B)|(?!\4)()(?:C))){3} ABC,带有分隔符D

S

2种模式(?:(?:(?!\1)()|\1(?:S))(?:(?!\2)()(?:A)|(?!\3)()(?:B)|(?!\4)()(?:C)|(?!\5)()(?:D))){4} A,没有B

S

3个模式(?:(?!\1)()(?:A)|(?!\2)()(?:B)){2} AB,没有C

S

4个模式(?:(?!\1)()(?:A)|(?!\2)()(?:B)|(?!\3)()(?:C)){3} ABC,没有D

S