Python 正则表达式:向后匹配最接近的值
是否有方法匹配包含特定值的所有节名,如下所示:Python 正则表达式:向后匹配最接近的值,python,regex,Python,Regex,是否有方法匹配包含特定值的所有节名,如下所示: 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,d
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
有没有办法匹配bbb
和ddd
谢谢
更新:
有一些解决方案(有效)基于以下假设:值行不包含冒号或不以空格开头。但是,是否有方法匹配值6
并获取其前面最近的部分,即即使值包含冒号或未缩进
NHAHDH的答案是:你不能用正则表达式向后搜索。有lookbehind(在本例中,它需要可变宽度lookbehind),但效率极低,Python默认re模块不支持任何形式的lookbehind
我的结论是:
这可以使用具有上述假设的纯正则表达式来实现,或者(我更喜欢)使用drewk建议的组合正则表达式python方法(该方法也有一些假设,即该部分必须包含值
)
更新2:
这就是我的结局。它似乎不受上述限制。它确实假设值不能有以节开始的行。*:
。我们将节与下一节进行匹配,但不包括它(通过使用(?=…)
语法),为了匹配最后一节,我们有\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
如果您只需要最后一部分:
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)]
编辑
看,没有冒号或缩进:
进口稀土
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
如果筛选出可能没有匹配“value”部分的部分很重要,请使用两个正则表达式,第一个正则表达式具有前瞻性:
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)
打印bbb
和ddd
section ([^:]+):[^:]+value 6 (DOTALL|MULTILINE)
当然,只有在“更多值”部分没有冒号的情况下,这才有效。假定节名不包含任何
:
,并且必须在行的开头声明一个有效的节,此解决方案将查找具有给定值的节的所有名称。必须使用多行
选项编译正则表达式
^section ([^:\n]+):.*\n( +.*\n)*( +value 6\b)
说明:
搜索行以^section([^:\n]+):..*\n
开始,后跟节名(假定不包含section
或新行字符),然后是:
。其余的:
与*\n
行匹配部分的其余部分
匹配至少有1个缩进空间的行。它确保我们不会“溢出”到下一节(++.*\n)*
匹配包含所需值的行(部分)<代码>\b确保(+value 6\b)
后面没有其他数字(63)、字母字符(6a)或下划线(6)6
某些值
包含冒号:
,此解决方案仍然有效
请注意,如果使用
LOCALE
标志或UNICODE
标志,则\b
的效果可能会有所不同。为什么要匹配aaa
和ccc
?让我们围绕第二个*?
创建第二个组,并查看它的输出:
>>> 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
,以便在搜索值6
时不会绕过新节的开头,而第一个消费者不会消费:
:
>>> re.findall(r'section ([^:]*?):(?:.(?!^section))*?value 6',text, re.M | re.S)
['bbb', 'ddd']
你为什么不把它解析成一个字典呢?匹配实际上是替换的一部分-我想从一个大文件中删除包含某个值的所有部分。它确实有效!它基于显式描述节内容格式的技巧(在本例中,从空格开始)。然而,问题是,有没有可能做到逻辑上似乎很容易做到的事情:找到“值6”并向后搜索第一个匹配部分:@Ivan:你不能用正则表达式向后搜索。有look-behind(在本例中,它需要可变宽度的look-behind),但效率极低,Python default
re
模块不支持任何形式的look-behind。@Jerry问题已编辑,示例不同。它仍然与初始示例不匹配。只添加了两个部分,一个包含值6
。它确实有效!它基于显式描述节内容格式的技巧(在本例中,值行不包含冒号)。然而,问题是,是否有可能做到逻辑上看起来很简单的事情:找到“值6”并向后搜索第一个匹配部分:谢谢,看起来将python逻辑与正则表达式相结合是最干净的。在这种情况下,纯正则表达式可以工作,但会变得复杂,并且有一定的假设(该节的内容具有一定的格式)如果某些节未包含值
,则将获取以下节中的第一个值,如果恰好等于6
,则尽管当前节未包含值参数,但仍将输出该节。例如,使用输入的''\section aaa:some values section bbb:more values section ccc尝试此代码:有些值为6'
。输出为[('aaa',0,94)]
,尽管aaa
没有值参数。@ovgolovin:是的,这是这里的假设(限制)。