查找重叠匹配项

2 投票
2 回答
581 浏览
提问于 2025-04-18 14:31

给定一个字符串(来自文本文件的一行),我想找到所有像这样构建的子字符串:

[[ words ]]

例如:

[[foo [[ bar ]]

应该返回这两个:

[[foo [[ bar ]]

[[ bar ]]

另一个例子:

[[foo]] 和 [[bar]]

应该产生:

[[foo]]

[[bar]]

我想到了一个公式:

\[\[.+\]\]

但它工作得不太好(匹配得太多了)。

谢谢大家的帮助!

2 个回答

1

这个内容使用了正向前瞻的方式来捕捉并返回你重叠的匹配结果:

>>> re.findall(r'(?=(\[\[.*?\]\]))', '[[foo [[ bar ]]')
# ['[[foo [[ bar ]]', '[[ bar ]]']

>>> re.findall(r'(?=(\[\[.*?\]\]))', '[[foo]] and [[bar]]')
# ['[[foo]]', '[[bar]]']

注意*这个量词后面有一个?,这让你的匹配变得不贪婪,也就是说它会尽量匹配最少的内容。

2

重叠匹配:使用前瞻

如果你想要懒惰的重叠匹配,可以使用这个正则表达式:

(?=(\[\[.?*\]\]))

在Python中:

import re
pattern = r"(?=(\[\[.*?\]\]))"
print(re.findall(pattern, "[[foo [[ bar ]]"))
print(re.findall(pattern, "[[foo]] and [[bar]]"))

输出结果:

['[[foo [[ bar ]]', '[[ bar ]]']
['[[foo]]', '[[bar]]']

如果你想要“贪婪的重叠”,可以使用 (?=(\[\[.*\]\]))

输出结果:

['[[foo [[ bar ]]', '[[ bar ]]']
['[[foo]] and [[bar]]', '[[bar]]']

解释

  • 前瞻 (?= ... ) 表示括号内的内容可以被匹配(但实际上并不匹配它,这样我们就能找到重叠的匹配)
  • 括号中的 `([[.*]])` 将匹配到的字符串捕获到第1组
  • \[\[ 匹配 [[
  • .* 贪婪地匹配任何字符
  • .*? 中,星号量词被 ? 变得“懒惰”,这样点号只会匹配所需的最少字符,以便下一个符号能够匹配(最短匹配)。如果没有 ?.* 会先匹配整个字符串,然后回溯到只需要的地方,以便下一个符号能够匹配(最长匹配)。
  • \]\] 匹配 ]]

参考资料

撰写回答