如果以色双音符在给定的结构中发生两次(即,就像在XML解析中一样),是否有办法找到字符串?显然,此代码无效,因为它找到了第一个标签,然后是最后一个关闭标签:
re.findall(r'<(.+)>([sS]*)</(.+)>', s)
因此,有没有办法告诉Regex,第三次匹配应与第一个比赛相同?
完整代码:
import re
s = '''<a1>
<a2>
1
</a2>
<b2>
52
</b2>
<c2>
<a3>
Abc
</a3>
</c2>
</a1>
<b1>
21
</b1>'''
matches = re.findall(r'<(.+)>([sS]*)</(.+)>', s)
for match in matches:
print(match)
结果应该是所有内容的标签:
[('a1', 'n <a2>n 1n </a2>n <b2>n 52n </b2>n <c2>n <a3>n Abcn </a3>n </c2>n'),
('a2', 'n 1n '),
...]
注意:我不是在寻找完整的XML解析包。问题特定是关于解决给定问题的问题。
您可以使用backeference和简单递归:
>>> def m(s):
... matches = re.findall(r'<(.+)>([sS]*)</(1)>', s)
... for k,s2,_ in matches:
... print (k,s2)
... m(s2)
...
>>> m(s)
('a1', 'n <a2>n ...[dropped]... </a3>n </c2>n')
('a2', 'n 1n ')
('b2', 'n 52n ')
('c2', 'n <a3>n Abcn </a3>n ')
('a3', 'n Abcn ')
('b1', 'n 21n')
更多有关Microsoft文档的反向表示的信息。
编辑
为发电机提供额外的乐趣。感谢@MrCarnivore您的建议删除if s
:
>>> def m(s):
... matches = re.findall(r'<(.+)>([sS]*)</(1)>', s)
... for k,s2,_ in matches:
... yield (k,s2)
... yield from m(s2)
...
>>> for x in m(s):
... x
...
('a1', 'n <a2> [....] Abcn </a3>n </c2>n')
('a2', 'n 1n ')
('b2', 'n 52n ')
('c2', 'n <a3>n Abcn </a3>n ')
('a3', 'n Abcn ')
('b1', 'n 21n')
我不会这样做,因为递归结构很难用Regexes解析。Python的re
模块不支持此。替代regex
模块可以。但是,我不会做。
反向注册只能带给您这么远:
import re
s = '''<a1>
<a2>
1
</a2>
<b2>
52
</b2>
<c2>
<a3>
Abc
</a3>
</c2>
</a1>
<b1>
21
</b1>'''
matches = re.findall(r'<(.+)>([sS]*)</1>', s) # mind the 1
for match in matches:
print(match)
它将为您提供两个匹配:1。<a1> ... </a1>
和<b1> ... </b1>
。
现在可以想象您的某些标签具有属性。如果标签可以跨越一行怎么办?关闭自己的标签呢?意外空间呢?
HTML/XML解析器可以处理所有这些。
使用帮助danihp
在答案中给了我,并遵守提示DDeMartini
在评论中给出的提示,我能够创建一个轻巧的XML解析器,该解析器返回XML的dict结构:
import re
def xml_loads(xml_text):
matches = re.findall(r'<([^<>]+)>([sS]*)</(1)>', xml_text)
if not matches:
return xml_text.strip()
d = {}
for k, s2, _ in matches:
d[k] = xml_loads(s2)
return d
s = '''<a1>
<a2>
1
</a2>
<b2>
52
</b2>
<c2>
<a3>
Abc
</a3>
</c2>
</a1>
<b1>
21
</b1>'''
d = xml_loads(s)
print(d)