合并连续匹配项并将非连续匹配项与 from re findall 分开

combining consecutive matches and separating non-consecutive matches with from re findall

我有一个格式的字符串:

my_string = 'hello|foo world|foo how|bar are|bar you|bar today|foo'

我想要 return 一个列表,其中 foo 后的所有连续单词都分组在同一个字符串中,但中间带有“|bar”的单词在不同的字符串中。如果我尝试重复前瞻:

re.findall(r'(\w+(?=\|foo\b))+',my_string)

returns

['hello', 'world', 'today']

不过我想return是

['hello world', 'today']

因为'hello'和'world'没有被非foo字分隔。

在我的实际问题中,'foo'后面的单词序列在被搜索的字符串中出现的次数是未知的,'bar'可能是几种不同的模式。

我可以通过几个替换来解决它,首先用一个拆分指示符替换所有非 foo 模式并在其上拆分,然后删除 foos 和剥离空格:

bars_removed = re.sub('(\w+\|(?!foo)[a-z]+ )+','split_string',my_string)
only_foo_words = [re.sub('\|foo','',x).strip() for x in bars_removed.split('split_string')]

哪个 return 是想要的结果,但我觉得有一种方法可以使用 findall 或我缺少的 finditer 来做到这一点。

您不能“排除”捕获到同一组的其他文本之间的文本。

您需要用消费模式替换 lookahead,提取所有连续的匹配项,然后仅使用 str.replace 方法删除 |foo 作为 post-processing 步骤。

final_list = [x.replace('|foo','') for x in re.findall(r'\w+\|foo(?:\s+\w+\|foo)*', my_string)]

参见 the regex demo

详情:

  • \w+ - 一个或多个单词字符
  • \|foo - |foo 字符串
  • (?:\s+\w+\|foo)* - non-capturing 组匹配零个或多个序列
    • \s+ - 一个或多个空格
    • \w+\|foo - 一个或多个单词字符,然后是一个 |foo 字符串。