Python正则如何捕获分隔符间重复捕获组的全部匹配结果
问题原因
你写的正则只能捕获到单个element的核心原因是:Python标准re库的捕获组有重复覆盖特性:当捕获组被+/*这类重复量词修饰时,最终只会保存最后一次匹配到的内容,所以你嵌套在(?:element (\d+)\n)+里的捕获组,只会保留最后一个匹配到的element编号,无法拿到所有匹配结果。
符合需求的实现方案
方案1:使用第三方regex模块(支持重复捕获堆栈,完全符合你要的单轮匹配捕获所有重复结果的需求)
regex模块是Python标准re库的增强版,支持保留捕获组的所有重复匹配结果,你可以直接用优化后的正则(用(?s)内联标志开启DOTALL模式,代替笨重的(?:.|\n)写法):
(?s)block (\d+).*?(?:element (\d+)\n)+.*?exit
调用代码示例:
import regex text = """block 1 <some other text here> element 1 element 2 element 3 <some other text here> <some other text here> exit block 2 <some other text here> element 1 element 2 <some other text here> <some other text here> exit """ # 遍历每个block的匹配结果 for match in regex.finditer(r"(?s)block (\d+).*?(?:element (\d+)\n)+.*?exit", text): block_id = match.group(1) # captures()方法可以直接拿到该捕获组所有重复匹配的结果 elements = match.captures(2) print(f"block {block_id}的elements: {elements}")
输出结果:
block 1的elements: ['1', '2', '3'] block 2的elements: ['1', '2']
方案2:标准re库实现(不使用findall/split)
如果你不想引入第三方依赖,可以用两步匹配实现,先用正则匹配出每个完整的block块,再在每个块内匹配所有element:
import re text = """block 1 <some other text here> element 1 element 2 element 3 <some other text here> <some other text here> exit block 2 <some other text here> element 1 element 2 <some other text here> <some other text here> exit """ # 先匹配每个完整的block块 block_pattern = re.compile(r"(?s)block (\d+).*?exit") for block_match in block_pattern.finditer(text): block_id = block_match.group(1) block_content = block_match.group(0) # 在当前block内匹配所有element,使用finditer符合你不使用findall的要求 element_pattern = re.compile(r"element (\d+)") elements = [em.group(1) for em in element_pattern.finditer(block_content)] print(f"block {block_id}的elements: {elements}")
输出结果和方案1完全一致。
补充说明
如果你一定要用标准re库在单个正则里一次性捕获所有element,是无法实现的,这是标准re库的设计限制,只能借助第三方regex模块的重复捕获功能实现。
内容的提问来源于stack exchange,提问作者Monica
相关产品推荐
相关产品推荐

