我在Python中的正则表达式没有正确递归
我想要抓取一个标签里面的所有内容,以及它后面的几行,但应该在遇到下一个括号时停止。我哪里做错了呢?
import re #regex
regex = re.compile(r"""
^ # Must start in a newline first
\[\b(.*)\b\] # Get what's enclosed in brackets
\n # only capture bracket if a newline is next
(\b(?:.|\s)*(?!\[)) # should read: anyword that doesn't precede a bracket
""", re.MULTILINE | re.VERBOSE)
haystack = """
[tab1]
this is captured
but this is suppose to be captured too!
@[this should be taken though as this is in the content]
[tab2]
help me
write a better RE
"""
m = regex.findall(haystack)
print m
我想要得到的是:
[('tab1', '这部分被抓取了\n但这部分也应该被抓取!\n@[这部分应该被抓取,因为它在内容里面]\n', '[tab2]','帮我\n写一个更好的正则表达式\n')]
补充:
regex = re.compile(r"""
^ # Must start in a newline first
\[(.*?)\] # Get what's enclosed in brackets
\n # only capture bracket if a newline is next
([^\[]*) # stop reading at opening bracket
""", re.MULTILINE | re.VERBOSE)
这个方法似乎有效,但它也把内容里面的括号给去掉了。
3 个回答
2
这个代码能满足你的需求吗?
regex = re.compile(r"""
^ # Must start in a newline first
\[\b(.*)\b\] # Get what's enclosed in brackets
\n # only capture bracket if a newline is next
([^[]*)
""", re.MULTILINE | re.VERBOSE)
这个代码会返回一个包含多个元组的列表,每个元组里有两个元素(每次匹配会生成一个这样的元组)。如果你想要一个扁平化的元组,可以这样写:
m = sum(regex.findall(haystack), ())
3
首先,为什么要用正则表达式来解析呢?你会发现自己无法找到问题的根源,因为正则表达式不会给你任何反馈。而且在这个正则表达式里也没有使用递归。
让你的生活简单一点:
def ini_parse(src):
in_block = None
contents = {}
for line in src.split("\n"):
if line.startswith('[') and line.endswith(']'):
in_block = line[1:len(line)-1]
contents[in_block] = ""
elif in_block is not None:
contents[in_block] += line + "\n"
elif line.strip() != "":
raise Exception("content out of block")
return contents
你可以通过异常处理来捕捉错误,同时还能调试执行过程,这可是额外的好处。此外,你还可以得到一个字典作为结果,这样在处理时就能应对重复的部分。我的结果是:
{'tab2': 'help me\nwrite a better RE\n\n',
'tab1': 'this is captured\nbut this is suppose to be captured too!\n@[this should be taken though as this is in the content]\n\n'}
现在正则表达式被过度使用了……
3
我知道Python的正则表达式不支持递归。
补充说明:不过在你的情况下,这样做是可以的:
regex = re.compile(r"""
^ # Must start in a newline first
\[(.*?)\] # Get what's enclosed in brackets
\n # only capture bracket if a newline is next
([^\[]*) # stop reading at opening bracket
""", re.MULTILINE | re.VERBOSE)
补充说明2:是的,这样做并不能完全正确。
import re
regex = re.compile(r"""
(?:^|\n)\[ # tag's opening bracket
([^\]\n]*) # 1. text between brackets
\]\n # tag's closing bracket
(.*?) # 2. text between the tags
(?=\n\[[^\]\n]*\]\n|$) # until tag or end of string but don't consume it
""", re.DOTALL | re.VERBOSE)
haystack = """[tag1]
this is captured [not a tag[
but this is suppose to be captured too!
[another non-tag
[tag2]
help me
write a better RE[[[]
"""
print regex.findall(haystack)
不过我同意viraptor的看法。正则表达式很酷,但用它们来检查文件错误是不行的。也许可以考虑混合使用?:P
tag_re = re.compile(r'^\[([^\]\n]*)\]$', re.MULTILINE)
tags = list(tag_re.finditer(haystack))
result = {}
for (mo1, mo2) in zip(tags[:-1], tags[1:]):
result[mo1.group(1)] = haystack[mo1.end(1)+1:mo2.start(1)-1].strip()
result[mo2.group(1)] = haystack[mo2.end(1)+1:].strip()
print result
补充说明3:这是因为^
这个字符在[^方括号]
里面表示负匹配,而在其他地方则表示字符串的开始(或者在re.MULTILINE
模式下表示行的开始)。在正则表达式中,没有好的方法来进行负字符串匹配,只有字符匹配。