我正在尝试创建一种字典解析器。在文本文件中,我有以下格式的文本:
<topic>some_title1:<start>
test_text<end>
<topic>title_2:<start>
test1
test2<end>
在每种情况下,<topic>
表示密钥,<start>
和<end>
之间的文字是值。键总是一行,而值可能(并且很可能会)多于一行。
我的正则表达式如下:
p = re.compile("<topic>(.+):<start>\n(.+)<end>")
我正在使用p.findall(data)
来获取键/值对。
如果没有re.DOTALL
,我只会得到一个匹配,这是第一个匹配(some_title1
,其值为test_text
)。但是,我需要两场比赛。
所以,我尝试使用re.DOTALL
。
另一方面,这也给出了一个匹配,但不正确:
some_title1:<start>\ntest_text<end>\n\n<topic>title_2
,其对应值为test1\ntest2
。
我该如何解决这个问题?我(希望)希望保持类似标签的结构。
答案 0 :(得分:3)
你可以试试这个:
>>> import re
>>> t = '''<topic>some_title1:<start>
test_text<end>
<topic>title_2:<start>
test1
test2
<end>'''
>>> q = re.findall(r'<topic>([^:<]+?):<start>([^<]+?)<end>', t)
[('some_title1', '\ntest_text'), ('title_2', '\ntest1\ntest2\n')]
>>> dict(q)
{'some_title1': '\ntest_text', 'title_2': '\ntest1\ntest2\n'}
或者在一行中:
>>> dict(re.findall(r'<topic>([^:<]+?):<start>([^<]+?)<end>', t))
{'some_title1': '\ntest_text', 'title_2': '\ntest1\ntest2\n'}
这可以捕获多行值。当然,xml在这里工作会更好。但根据您的数据结构,关键似乎是通过匹配>
以外的任何字符来收集<
和<
之间的文字。换句话说,您的密钥应与此组匹配:([^:<]+?)
。您的值应与此组匹配:([^<]+?)
。
答案 1 :(得分:2)
如果您可以用其他方式表示数据,这将更容易。假设您代表您的数据:
<topic title="some title1">test_text1</topic>
<topic title="some title2">test_text2</topic>
现在可以使用BeautifulSoup轻松访问标题和内容:
from bs4 import BeautifulSoup
xml = """
<topic title="some title1">test_text1</topic>
<topic title="some title2">test_text2</topic>
"""
soup = BeautifulSoup(xml)
for topic in soup.find_all('topic'):
print topic['title'], topic.text
这将产生
some title1 test_text1
some title2 test_text2