我正在使用正则表达式与python并试图找出匹配模式的最佳方法,其中我正在搜索的两个单词的顺序无关紧要,但它们必须相邻。例如,我正在搜索短语"fat cat lasagna co"
或"cat fat lasagna co"
,我不得不想象有一种比r"\b(fat cat|cat fat) lasagna co\b"
更好的方法
我读过this question,它解决了类似的问题,但这些词语不必相邻,也无法弄清楚如何将其应用于我的问题。
答案 0 :(得分:1)
没有严格的更好的解决方案,但还有另一种选择。
现在,如果您有两个正常的词,如“胖”和“猫”,那么(fat cat|cat fat)
无疑是最佳解决方案。但如果你有5个单词怎么办?或者,如果您的模式比fat
和cat
更复杂,那么您不想输入两次?
代替fat
和cat
,您有3个正则表达式A
,B
和C
,而不是{{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
。)
如果我们设置|
= A
,fat
= B
和cat
=空格,我们会得到:
S
本质上,我们使用捕获组来“记住”哪些模式已经匹配。为此,我们在这里使用这个小模式:
(?:(?:(?!\1)()|\1 )(?:(?!\2)()fat|(?!\3)()cat)){2}
这是做什么的?这是一个恰好匹配一次的正则表达式。一旦匹配,它将永远不会再匹配。如果您尝试围绕该模式添加量词,例如(?!\1)()some_pattern
,那么它将匹配一次或根本不匹配。
在该组甚至已定义之前,有一个backreference用于捕获组的技巧。由于捕获组初始化为“无法匹配”状态,negative lookahead (?:(?!\1)()some_pattern)*
将成功匹配 - 但仅限第一次。因为之后,捕获组(?!\1)
匹配并捕获空字符串。从现在开始,否定前瞻()
将再也不会匹配。
将此作为构建基块,我们可以创建一个匹配(?!\1)
和fatcat
的正则表达式,同时只包含单词catfat
和fat
一次:
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}
,A
和B
,带有分隔符C
:
S
4个模式(?:(?:(?!\1)()|\1(?:S))(?:(?!\2)()(?:A)|(?!\3)()(?:B)|(?!\4)()(?:C))){3}
,A
,B
和C
,带有分隔符D
:
S
2种模式(?:(?:(?!\1)()|\1(?:S))(?:(?!\2)()(?:A)|(?!\3)()(?:B)|(?!\4)()(?:C)|(?!\5)()(?:D))){4}
和A
,没有B
:
S
3个模式(?:(?!\1)()(?:A)|(?!\2)()(?:B)){2}
,A
和B
,没有C
:
S
4个模式(?:(?!\1)()(?:A)|(?!\2)()(?:B)|(?!\3)()(?:C)){3}
,A
,B
和C
,没有D
:
S