正则表达式:匹配两个字符串之间的所有字符

Regex: Match all characters between two strings

示例:在荷兰,花生酱被称为 "pindakaas"(花生奶酪)而不是 "pindaboter"(花生酱),因为黄油这个词只用于使用含有真正黄油的产品。

我想匹配 cheesebutter 之间的所有内容,反之亦然。

目标:

编辑: 使用的语言是 Python 3.7,我使用的当前正则表达式是 cheese(.*?)butter.

你的例子中的问题是,你的第一个目标的最后一个词是源字符串中第二个目标的第一个词; "normal" RegEx 语法使 RE 引擎消耗它匹配的字符,即这些字符不可用于进一步匹配。

原则上,您可以使用像 PCRE 这样的 Regex 风格,在前瞻断言中使用捕获组来做到这一点,因为它们不会导致断言中的字符消耗。但是,所有断言都以性能为代价。比赛将在两个捕获组中进行。两个例子:

直接方法:

/
\b(?=(.*?cheese))butter  # match butter, assert that cheese comes after it and capture
|                        # or
\b(?=(.*?butter))cheese  # match cheese, assert that butter comes after it and capture
/gsx                     # flags: global, single line, free spacing

让我们看看\b(?=(.*?cheese))butter的成功匹配是如何工作的;另一个备选方案也反映了同样的原则。正则表达式引擎首先寻找单词边界\b,即文本中两边都没有单词字符的位置。一旦找到,它将尝试在此位置断言 (?=(.*?cheese))。在自然语言中:"Starting here, find cheese as soon as possible. Only if you find it, capture the whole string you just traversed in a numbered group and return the match pointer to where we started. Then, allow matching to continue." 如果断言成功,则匹配继续,接下来使用 butter。我们有我们的匹配项,匹配指针位于 butter 后面,正则表达式引擎在文本的其余部分尝试相同的事情(当然包括备选方案)。

参见 regex demo

稍微优化的版本:

/
\b(?=((?:[^c]*+|c(?!heese))*cheese))butter
|
\b(?=((?:[^b]*+|b(?!utter))*butter))cheese
/gsx

参见 regex demo

输出:

Match 1
Full match  27-33   butter
Group 1.    27-70   butter is called "pindakaas" (peanut cheese

Match 2
Full match  64-70   cheese
Group 2.    64-111  cheese) rather than "pindaboter" (peanut butter

如果有人不反对在事后为每个匹配连接匹配的字符串和捕获的字符串,这也可以工作,并且在性能方面会更好。 (仍然可能不如 Booboo 的回答中看到的 overlap 解决方案。)

/\bbutter\b.*?\b(?=(cheese))|\bcheese\b.*?\b(?=(butter))/sg

这只会匹配每个选项直到第二个词之前的单词边界,这允许下一次匹配尝试以该词开始。第二项不是匹配字符串的一部分,而是存储在捕获的组中:['butter is called "pindakaas" (peanut ', 'cheese'], etc..

参见 regex demo

如果您从 PyPI 存储库安装 regex 软件包,那么您可以进行 overlapped 搜索:

import regex as re

text = 'In the Netherlands, peanut butter is called "pindakaas" (peanut cheese) rather than "pindaboter" (peanut butter) because the word butter is only supposed to be used with products that contain actual butter.'

l = re.findall(r'\bbutter\b.*?\bcheese\b|\bcheese\b.*?\bbutter\b', text, overlapped=True)
print(l)

打印:

['butter is called "pindakaas" (peanut cheese', 'cheese) rather than "pindaboter" (peanut butter']

我使用了你的基本正则表达式,但要求 buttercheese 位于单词边界上,例如\bbutter\b,在单词前后放置 \b。随意删除或不删除。