2

有没有办法匹配包含某个值的所有部分名称,如下所示:

section aaa:
   some values
   value 5
section bbb:
   more values
   value 6
section ccc:
   some values
   value 5
section ddd:
   more values
   value 6

例如:

section (.*?):.*?value 6  (DOTALL|MULTILINE)

将匹配aaa,ccc而不是bbb, ddd

有没有办法匹配bbbddd

谢谢

更新:有一些解决方案(有效)基于值行不包含冒号或不以空格开头的假设。然而,有没有办法匹配value 6并获得它之前最接近的部分,即即使值包含冒号或没有缩进?

nhahtdh 的回答:你不用正则表达式向后搜索。有look-behind(这种情况下需要变宽look-behind),但是效率极低,Python默认re模块不支持任何形式的look-behind

我的结论:这可以通过带有上述假设的纯正则表达式来完成,或者(我的首选)是使用drawk建议的组合正则表达式-python方法(它也有一些假设,即该部分必须包含value

更新2:这就是我最终的结果。它似乎在没有上述限制的情况下工作。它确实假设值不能以 开头section .*:。我们将该部分匹配到下一个部分,但不包括它(通过使用(?=...)语法),并且为了匹配我们拥有的最后一个部分,\Z它是字符串的结尾。

for m in re.finditer(r'^section (.*?):(.*?)(?=(^section .*:)|\Z)', str1, re.MULTILINE | re.DOTALL):
    section = m.group(1)
    values = m.group(2)    
    if "value 6" in values:
        print section
4

4 回答 4

3
section ([^:]+):[^:]+value 6  (DOTALL|MULTILINE)

当然,这只有在“更多值”部分没有冒号时才有效

于 2013-05-25T19:26:53.670 回答
2

如果您只想要最后一部分:

print re.findall(r'^section (\w+):',tgt,flags=re.MULTILINE)[-1]

通过您的编辑,可以做到这一点:

import re

tgt='''\
section aaa:
   some values
   value 5
section bbb:
   more values
   value 6
section ccc:
   some values
   value 5
section ddd:
   more values
   value 6'''

pat=re.compile(r'^section (\w+):.*?value (\d+)',flags=re.MULTILINE|re.DOTALL)

print [(m.group(1),m.start(),m.end()) 
          for m in pat.finditer(tgt)
          if m.group(2)=='6']

印刷:

[('bbb', 39, 77), ('ddd', 117, 155)]

编辑

看 ma,没有冒号或缩进:

重新进口

tgt='''\
section aaa:
   some values
   value 5
section bbb
   more values
value 6
section ccc:
   some values
   value 5
section ddd:
   more values
   value 6'''

pat=re.compile(r'^section (\w+).*?^\s*value (\d+)',flags=re.MULTILINE|re.DOTALL)

print [(m.group(1),m.start(),m.end()) 
          for m in pat.finditer(tgt)
          if m.group(2)=='6']

相同的输出

编辑 2

如果过滤掉可能没有匹配“值”部分的部分很重要,请使用两个正则表达式,第一个向前看:

import re

tgt='''\
section aaa:
   some values

section bbb:
   more values
   value 6
section ccc:
   some values
   value 5
section ddd:
   more values
   value 6'''

pat1=re.compile(r'^section (\w+):(.*?)(?=section|\Z)',flags=re.MULTILINE|re.DOTALL)
pat2=re.compile(r'^\s*value (\d+)',flags=re.MULTILINE)

for m in pat1.finditer(tgt):
    m2=re.search(r'^\s*value (\d+)',m.group(2),flags=re.MULTILINE)
    if m2 and m2.group(1)=='6':
        print m.group(1)

印刷品bbbddd

于 2013-05-25T19:22:20.463 回答
2

假设节名不包含任何:,并且必须section 在行首声明有效节,此解决方案将找到具有给定值的节的所有名称。正则表达式必须使用MULTILINE选项编译。

^section ([^:\n]+):.*\n( +.*\n)*( +value 6\b)

解释:

  • ^section ([^:\n]+):.*\n搜索以 开头的行section ,后跟节名(假定不包含:换行符),然后是:. 其余部分.*\n与该section行的其余部分匹配。
  • ( +.*\n)*匹配至少有 1 个缩进空间的行。它确保我们不会“溢出”到下一部分。
  • ( +value 6\b)匹配(部分)包含所需值的行。\b确保6后面没有其他数字 (63)、字母字符 (6a) 或下划线 (6_)。

即使some values包含冒号,此解决方案也将起作用:

演示

请注意,如果使用flag 或flag,效果\b可能会有所不同。LOCALEUNICODE

于 2013-05-25T19:37:39.210 回答
0

为什么aaaccc匹配?让我们在 second 左右创建第二个组.*?,看看它输出什么:

>>> re.findall(r'section (.*?):(.*?)value 6',text, re.M | re.S)
[('aaa', '\n   some values\n   value 5\nsection bbb:\n   more values\n   '), ('ccc', '\n   some values\n   value 5\nsection ddd:\n   more values\n   ')]

由此我们可以看到,第二组捕获的内容超出了应有的范围。

为避免这种情况,请确保.第二个非贪婪消费者中的每一个都没有被跟随,^section因为它不会在搜索时绕过新部分的开头value 6并且第一个不消费:

>>> re.findall(r'section ([^:]*?):(?:.(?!^section))*?value 6',text, re.M | re.S)
['bbb', 'ddd']
于 2013-05-25T19:46:18.417 回答