在python中将文件解析为字典

在python中将文件解析为字典,python,file,python-2.7,dictionary,Python,File,Python 2.7,Dictionary,我有一个文件,你可以在下面看到它的一小部分: Clutch001 Albino X Pastel Bumble Bee X Albino Lesser Clutch002 Bee X Fire Bee Albino Cinnamon X Albino Mojave X Bumble Bee Clutch003 Black Pastel X Banana Ghost Lesser .... ClucthXXX和next CHXXX之间的字符串数可能不同,但不等于零。 我想知道是否有可能以某种方式

我有一个文件,你可以在下面看到它的一小部分:

Clutch001
Albino X Pastel
Bumble Bee X Albino Lesser
Clutch002
Bee X Fire Bee
Albino Cinnamon X Albino
Mojave X Bumble Bee
Clutch003
Black Pastel X Banana Ghost Lesser
....
ClucthXXX和next CHXXX之间的字符串数可能不同,但不等于零。 我想知道是否有可能以某种方式从一个文件中获取一个特定的字符串作为键(在我的例子中,它应该是xxx),并将文本作为字典的值,直到该特定字符串的第二次出现? 我想收到这样的词典:

d={'Clutch001': 'Albino X Pastel, Bumble Bee X Albino Lesser'
   'Clutch002': 'Bee X Fire Bee, Albino Cinnamon X Albino, Mojave X Bumble Bee'
   'Clutch003': 'Black Pastel X Banana Ghost Lesser'}
with open(filename) as inputfile:
    d = {clutch: ', '.join(lines) for clutch, lines in per_clutch(inputfile)}

我最感兴趣的部分是我们获取字符串模式并将其保存为键,然后将文本保存为值。任何有用方法的建议或指导都将不胜感激。

收集列表中的行,同时将该列表存储在词典中:

d = {}
values = None
with open(filename) as inputfile:
    for line in inputfile:
        line = line.strip()
        if line.startswith('Clutch'):
            values = d[line] = []
        else:
            values.append(line)
这将为您提供:

{'Clutch001': ['Albino X Pastel', 'Bumble Bee X Albino Lesser']
 'Clutch002': ['Bee X Fire Bee', 'Albino Cinnamon X Albino', 'Mojave X Bumble Bee']
 'Clutch003': ['Black Pastel X Banana Ghost Lesser']}
加载文件后,很容易将所有这些列表转换为单个字符串:

d = {key: ', '.join(value) for key, value in d.items()}
import re

tokens = iter(re.split(r'(^Clutch\d{3}\s*$)\s+', file.read(), flags=re.M))
next(tokens) # skip until the first Clutch
print({k: ', '.join(v.splitlines()) for k, v in zip(tokens, tokens)})
您也可以在读取文件时进行连接;我将使用生成器函数分组处理文件:

def per_clutch(inputfile):
    clutch = None
    lines = []
    for line in inputfile:
        line = line.strip()
        if line.startswith('Clutch'):
            if lines:
                yield clutch, lines
            clutch, lines = line, []
        else:
            lines.append(line)
    if clutch and lines:
        yield clutch, lines
然后只需将所有组读入字典:

d={'Clutch001': 'Albino X Pastel, Bumble Bee X Albino Lesser'
   'Clutch002': 'Bee X Fire Bee, Albino Cinnamon X Albino, Mojave X Bumble Bee'
   'Clutch003': 'Black Pastel X Banana Ghost Lesser'}
with open(filename) as inputfile:
    d = {clutch: ', '.join(lines) for clutch, lines in per_clutch(inputfile)}
后者的演示:

>>> def per_clutch(inputfile):
...     clutch = None
...     lines = []
...     for line in inputfile:
...         line = line.strip()
...         if line.startswith('Clutch'):
...             if lines:
...                 yield clutch, lines
...             clutch, lines = line, []
...         else:
...             lines.append(line)
...     if clutch and lines:
...         yield clutch, lines
... 
>>> sample = '''\
... Clutch001
... Albino X Pastel
... Bumble Bee X Albino Lesser
... Clutch002
... Bee X Fire Bee
... Albino Cinnamon X Albino
... Mojave X Bumble Bee
... Clutch003
... Black Pastel X Banana Ghost Lesser
... '''.splitlines(True)
>>> {clutch: ', '.join(lines) for clutch, lines in per_clutch(sample)}
{'Clutch001': 'Albino X Pastel, Bumble Bee X Albino Lesser', 'Clutch002': 'Bee X Fire Bee, Albino Cinnamon X Albino, Mojave X Bumble Bee', 'Clutch003': 'Black Pastel X Banana Ghost Lesser'}
>>> from pprint import pprint
>>> pprint(_)
{'Clutch001': 'Albino X Pastel, Bumble Bee X Albino Lesser',
 'Clutch002': 'Bee X Fire Bee, Albino Cinnamon X Albino, Mojave X Bumble Bee',
 'Clutch003': 'Black Pastel X Banana Ghost Lesser'}

这是一个或多或少能起作用的版本。我不确定它有多像蟒蛇(它可能会被挤压,而且肯定会被改进):

输出(重复信息)为:

如果由于某种原因,第一行不是“离合器”行,则会因为空键而出现错误

使用逗号连接、处理断开的文本文件(末尾没有换行符)等:

“pad”技术是我在其他情况下喜欢的一种技术,在这里效果很好。不过,我相当肯定这不会被视为肾盂

修订样本输出:

{'Clutch001': 'Albino X Pastel, Bumble Bee X Albino Lesser', 'Clutch002': 'Bee X Fire Bee, Albino Cinnamon X Albino, Mojave X Bumble Bee', 'Clutch003': 'Black Pastel X Banana Ghost Lesser'}
'Clutch001': 'Albino X Pastel, Bumble Bee X Albino Lesser'
'Clutch002': 'Bee X Fire Bee, Albino Cinnamon X Albino, Mojave X Bumble Bee'
'Clutch003': 'Black Pastel X Banana Ghost Lesser'
如注释中所述,如果可以依靠“离合器”(或任何关键字)不出现在非关键字行中,则可以使用以下选项:

keyword = "Clutch"
with open(filename) as inputfile:
    t = inputfile.read()
    d = {keyword + s[:3]: s[3:].strip().replace('\n', ', ') for s in t.split(keyword)}
这会一次将整个文件读取到内存中,因此如果文件可能变得非常大,则应避免执行此操作。

您可以使用枚举文件中的
“离合器”
部分:

d = {key: ', '.join(value) for key, value in d.items()}
import re

tokens = iter(re.split(r'(^Clutch\d{3}\s*$)\s+', file.read(), flags=re.M))
next(tokens) # skip until the first Clutch
print({k: ', '.join(v.splitlines()) for k, v in zip(tokens, tokens)})
假设单词Clutch单独出现在它自己的行上,则以下操作将起作用:

import re
d = {}
with open(filename) as f:
for line in f:
    if re.match("^Clutch[0-9]+", line) :
        match = line   # match is the key searched for
        match = match.replace('\n', ' ')    # newlines are replaced
        d[match] = ''
    else:
        line = line.replace('\n', ' ')
        d[match] += line  # all lines without the word 'Clutch'
                          # are added to the matched key

让文件“file.txt”包含:

Clutch001 Albino X Pastel Bumble Bee X Albino Lesser Clutch002 Bee X Fire Bee Albino Cinnamon X Albino Mojave X Bumble Bee Clutch003 Black Pastel X Banana Ghost Lesser
带数字的离合器是否总是单独在一行?@JonathanLeffler是的,它总是单独在一行?
clutch
这个词是否可能出现在任何其他行中?如果没有,您可以使用
.split('Clutch')
,但后面有数字,是否可以在split中使用regex?请参阅下面的答案。只要关键字(“离合器”)的字母部分不出现在其他地方,就不需要正则表达式。@BallPython:不,直接在文件上迭代就足够了;它根据需要读取行。values是非类型对象,因此,它没有appendattribute@BallPython:那么您的第一行不是以
'Clutch'
开头;只有在遇到以“离合器”开头的行时,才会将
值设置为列表。加上一行,
值=d[line]=[]
非常令人惊讶。我会使用您的第一个代码,但其他方法有什么好处,它们与第一个方法的简单性不匹配这不会用逗号连接字符串。此外,您确实应该使用
str.strip()
str.rstrip()
删除行中的空白(最后一行并不总是有新行,因此
行[0:-1]
将删除错误的字符,或者如果文件在Windows上以本机换行符模式打开,则最终会出现尾随
\r
)。
str.strip()
删除前导空格和尾随空格(至少默认情况下);现在还不清楚这是否可以。从技术上讲,文本文件必须以换行符结尾——但我知道草率的编辑器(人和程序)可以让文本文件没有尾随的换行符。不过,我怀疑这是Windows上比Unix更常见的问题。我正在处理加入的内容。示例开始时没有空格;我还提到了str.rstrip()
。如果希望在手术中精确,并且必须保留其他空白,请使用
line.rstrip('\r\n')
。然而,这种用例是相当罕见的。目前,Martin的更适合您所陈述的需求。如果你的要求更灵活,那么我的可能更简单。即便如此,仍有一些改进需要改进。 Clutch001 Albino X Pastel Bumble Bee X Albino Lesser Clutch002 Bee X Fire Bee Albino Cinnamon X Albino Mojave X Bumble Bee Clutch003 Black Pastel X Banana Ghost Lesser
import re

with open('file.txt', 'r') as f:
    result = re.split(
        r'(Clutch\d{3}).*?',
        f.read(),
        flags=re.DOTALL # including '\n'
    )[1:] # result is ['Clutch001', '\nAlbino X Pastel\nBumble Bee X Albino Lesser\n', 'Clutch002', '\nBee X Fire Bee\nAlbino Cinnamon X Albino\nMojave X Bumble Bee\n', 'Clutch003', '\nBlack Pastel X Banana Ghost Lesser\n']

    keys = result[::2] # keys is ['Clutch001', 'Clutch002', 'Clutch003']
    values = result[1::2] # values is ['\nAlbino X Pastel\nBumble Bee X Albino Lesser\n', '\nBee X Fire Bee\nAlbino Cinnamon X Albino\nMojave X Bumble Bee\n', '\nBlack Pastel X Banana Ghost Lesser\n']

    values = map(
        lambda value: value.strip().replace('\n', ', '),
        values
    ) # values is ['Albino X Pastel, Bumble Bee X Albino Lesser', 'Bee X Fire Bee, Albino Cinnamon X Albino, Mojave X Bumble Bee', 'Black Pastel X Banana Ghost Lesser']

    d = dict(zip(keys, values)) # d is {'Clutch001': 'Albino X Pastel, Bumble Bee X Albino Lesser', 'Clutch002': 'Bee X Fire Bee, Albino Cinnamon X Albino, Mojave X Bumble Bee', 'Clutch003': 'Black Pastel X Banana Ghost Lesser'}