【问题标题】:regex with optional block of text带有可选文本块的正则表达式
【发布时间】:2025-12-28 05:20:07
【问题描述】:

我正在使用正则表达式解析结构化文本,如下所示,插入符号标记我要匹配的内容:

block 1
^^^^^^^
    subblock 1.1
        attrib a=a1
    subblock 1.2
        attrib b=b1
                 ^^
block 2
    subblock 2.1
        attrib a=a2
block 3
^^^^^^^
    subblock 3.1
        attrib a=a3
    subblock 3.2
        attrib b=b3
                 ^^

子块可能会出现在块内,也可能不会出现,例如:子块 2.2.

预期的匹配是[(block1,b1), (block3,b3)]

/(capture block#)[\s\S]*?attrib\sb=(capture b#)/gm

但这最终匹配 [(block1, b1), (block2, b3)].

我在哪里做错了正则表达式?

【问题讨论】:

  • 您总是需要子块的b 属性?您能否也提供此语句的完整示例...子块可能出现也可能不出现在块内...那里的预期输出是什么?
  • 什么是(捕获b#)
  • @AKS 是的,总是需要“b”属性。如果应该包含此属性的子块不存在于特定块中,我只想跳过该块并继续下一个。如上例所示,block2 没有 subblock2.2,它包含属性“b”。所以我只是丢弃了这个块。
  • @WiktorStribiżew 通过(捕获 b#)我的意思是捕获组中的正则表达式来选择值“b#”。在上面的示例中,只需 (\D\d)。但是属性的值本身可能需要复杂的正则表达式。

标签: python regex parsing


【解决方案1】:

你可以使用

(?m)(^block\s*\d+).*(?:\n(?!block\s*\d).*)*\battrib\s*b=(\w+)

the regex demo

正则表达式基于展开循环技术。这是一个解释:

  • (?m) - 使^ 匹配行首的多行修饰符
  • (^block\s*\d+) - 匹配并捕获 block + 可选空格 + 1+ 数字(第 1 组)
  • .* - 匹配 的其余部分(因为不应打开 DOTALL 选项)
  • (?:\n(?!block\s*\d).*)* - 匹配后面不是单词的任何文本 block 后跟可选的空格,后跟数字(这样就设置了边界)
  • \battrib\s*b=(\w+) - 匹配整个单词 attrib 后跟 0+ 个空格,文字 b=,并匹配并捕获 1+ 个字母数字或下划线(注意:这可以根据您的真实数据进行调整)(\w+)

Python demo:

import re
p = re.compile(r'(?m)(^block\s*\d+).*(?:\n(?!block\s*\d).*)*\battrib\s*b=(\w+)')
s = "block 1\n    subblock 1.1\n        attrib a=a1\n    subblock 1.2\n        attrib b=b1\nblock 2\n    subblock 2.1\n        attrib a=a2\nblock 3\n    subblock 3.1\n        attrib a=a3\n    subblock 3.2\n        attrib b=b3"
print(p.findall(s))

【讨论】:

【解决方案2】:

这个正则表达式呢? https://regex101.com/r/yZ4fL9/1

block (\d).*?attrib b=b(\1)

【讨论】: