使用正则表达式分组将字符串转换为字典

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()可以接受二元组的迭代