使用正则表达式分组将字符串转换为字典
Convert a string to a dictionary using regex-grouping
我有很多这样格式的 txt 文件 -
\n==== Intro \n text \n text \n==== Body \n text \n text \n==== Refs \n test \n text
我想将它们放入字典中,如下所示 -
{'Intro': '\n text \n text \n',
'Body': '\n text \n text',
'Refs': '\n test \n text'}
我担心处理所有 txt 文件将花费的时间,因此想要一种尽可能少的方法,我不关心将文本分成几行。
我正在尝试使用正则表达式,但很难让它正常工作 - 我认为我的最后一个正则表达式组不正确。以下是我目前拥有的。任何建议都会很棒。
pattern = r"(====.)(.+?\b)(.*)"
matches = re.findall(pattern, data, re.DOTALL)
my_dict = {b:c for a,b,c in matches}
应该这样做:
d = dict(re.findall('(?<=\n====\s)(\w+)(\s+[^=]+)', text, re.M | re.DOTALL))
print(d)
{'Body': ' \n text \n text \n',
'Intro': ' \n text \n text \n',
'Refs': ' \n test \n text'}
正则表达式详细信息
(?<= # lookbehind (must be fixed width)
\n # newline
==== # four '=' chars in succession
\s # single wsp character
)
( # first capture group
\w+ # 1 or more alphabets (or underscore)
)
( # second capture group
\s+ # one or more wsp characters
[^=]+ # match any char that is not an '='
)
这里不需要RegEx,可以使用经典的split()
函数。
这里,为了便于阅读,我使用textwrap
:
import textwrap
text = textwrap.dedent("""\
==== Intro
text
text
==== Body
text
text
==== Refs
test
text""")
你可以这样做:
result = {}
for part in text.split("==== "):
if not part.isspace():
section, content = part.split(' ', 1)
result[section] = content
或者用理解中的元组列表初始化一个dict
:
result = dict(part.split(' ', 1)
for part in text.split("==== ")
if not part.isspace())
你可以试试这个:
import re
s = "\n==== Intro \n text \n text \n==== Body \n text \n text \n==== Refs \n test \n text"
final_data = re.findall("(?<=\n\=\=\=\=\s)[a-zA-Z]+\s", s)
text = re.findall("\n .*? \n .*?$|\n .*? \n .*? \n", s)
final_body = {a:b for a, b in zip(final_data, text)}
输出:
{'Body ': '\n text \n text \n', 'Intro ': '\n text \n text \n', 'Refs ': '\n test \n text'}
如果不想将整个文件读入内存,可以这样逐行处理:
marker = "==== "
def read_my_custom_format(file):
current_header = None
current_contents = []
for line in file:
line = line.strip() # trim whitespace, including trailing newline
if line.startswith(marker):
yield current_header, current_contents # emit current section
current_header = line[len(marker):] # trim marker
current_contents = []
else:
current_contents.append(line)
这是一个生成元组而不是构建字典的生成器。
这样它一次只在内存中保存一个部分。
此外,每个键都映射到一个行列表而不是一个字符串,但您可以轻松地只 "".join(iterable)
它们。
如果你想生成一个单独的字典,它再次占用与输入文件成比例的内存,你可以这样做:
with open("your_textfile.txt") as file:
data = dict(read_my_custom_format(file))
因为dict()
可以接受二元组的迭代
我有很多这样格式的 txt 文件 -
\n==== Intro \n text \n text \n==== Body \n text \n text \n==== Refs \n test \n text
我想将它们放入字典中,如下所示 -
{'Intro': '\n text \n text \n',
'Body': '\n text \n text',
'Refs': '\n test \n text'}
我担心处理所有 txt 文件将花费的时间,因此想要一种尽可能少的方法,我不关心将文本分成几行。
我正在尝试使用正则表达式,但很难让它正常工作 - 我认为我的最后一个正则表达式组不正确。以下是我目前拥有的。任何建议都会很棒。
pattern = r"(====.)(.+?\b)(.*)"
matches = re.findall(pattern, data, re.DOTALL)
my_dict = {b:c for a,b,c in matches}
应该这样做:
d = dict(re.findall('(?<=\n====\s)(\w+)(\s+[^=]+)', text, re.M | re.DOTALL))
print(d)
{'Body': ' \n text \n text \n',
'Intro': ' \n text \n text \n',
'Refs': ' \n test \n text'}
正则表达式详细信息
(?<= # lookbehind (must be fixed width)
\n # newline
==== # four '=' chars in succession
\s # single wsp character
)
( # first capture group
\w+ # 1 or more alphabets (or underscore)
)
( # second capture group
\s+ # one or more wsp characters
[^=]+ # match any char that is not an '='
)
这里不需要RegEx,可以使用经典的split()
函数。
这里,为了便于阅读,我使用textwrap
:
import textwrap
text = textwrap.dedent("""\
==== Intro
text
text
==== Body
text
text
==== Refs
test
text""")
你可以这样做:
result = {}
for part in text.split("==== "):
if not part.isspace():
section, content = part.split(' ', 1)
result[section] = content
或者用理解中的元组列表初始化一个dict
:
result = dict(part.split(' ', 1)
for part in text.split("==== ")
if not part.isspace())
你可以试试这个:
import re
s = "\n==== Intro \n text \n text \n==== Body \n text \n text \n==== Refs \n test \n text"
final_data = re.findall("(?<=\n\=\=\=\=\s)[a-zA-Z]+\s", s)
text = re.findall("\n .*? \n .*?$|\n .*? \n .*? \n", s)
final_body = {a:b for a, b in zip(final_data, text)}
输出:
{'Body ': '\n text \n text \n', 'Intro ': '\n text \n text \n', 'Refs ': '\n test \n text'}
如果不想将整个文件读入内存,可以这样逐行处理:
marker = "==== "
def read_my_custom_format(file):
current_header = None
current_contents = []
for line in file:
line = line.strip() # trim whitespace, including trailing newline
if line.startswith(marker):
yield current_header, current_contents # emit current section
current_header = line[len(marker):] # trim marker
current_contents = []
else:
current_contents.append(line)
这是一个生成元组而不是构建字典的生成器。
这样它一次只在内存中保存一个部分。
此外,每个键都映射到一个行列表而不是一个字符串,但您可以轻松地只 "".join(iterable)
它们。
如果你想生成一个单独的字典,它再次占用与输入文件成比例的内存,你可以这样做:
with open("your_textfile.txt") as file:
data = dict(read_my_custom_format(file))
因为dict()
可以接受二元组的迭代