Python:将多行文本转换为字典

vecaoik1  于 2023-03-20  发布在  Python
关注(0)|答案(2)|浏览(243)

我有一个文本文件的格式(好吧,它是少得多的结构,但我需要的部分遵循下面的想法):

[ThisShouldBeAKey]
Value1=yes
Value2=no
Value3=fancywords
Value4=numbers

[ThisShouldBeAnotherKey]
Value2=true
Value3=333
Value5=qqq

我想把这个文件转换成字典,这样我就可以很容易地比较某些键的某些值。例如,检索[Key 1]和[Key 100]的Value 8和Value 9。
我想我可以通过简单地迭代[key]的文本转储来检索Value 8和Value 9,并使用startswith()或其他字符串函数来检索我想要的内容。因此,尽管你可以(理想地)创建一个嵌套字典,但我不认为我必须这样做。
然而,我甚至连简单地获取[Key]:Value 1Value 2 Value 3AllthevaluesTextdump的字典都有困难。我自己尝试过一些方法,我尝试过这里的建议(In Python, how do I read a file into a dictionary with multiple line entries?)和对它的修改,但我总是遇到for循环、while循环的问题,或者文件没有被正确读取。
您建议如何执行此操作?
先谢谢你!

erhoui1w

erhoui1w1#

在每一行上循环并检测起始方括号以开始一个新组。使用split获取其他行上的key和value以更新当前组:

result = dict()
for line in file:
    if line.startswith("["):
        result[line.strip("[] ")] = group = dict()
    elif "=" in line:
        group.update([line.strip().split("=",1)])

print(result)
{'ThisShouldBeAKey': {'Value1': 'yes', 'Value2': 'no', 
                      'Value3': 'fancywords', 'Value4': 'numbers'}, 
 'ThisShouldBeAnotherKey': {'Value2': 'true', 'Value3': '333',
                            'Value5': 'qqq'}}
rekjcdws

rekjcdws2#

您可以只使用<dict>.setdefault<str>.split迭代行

filepath = 'x.txt' #<-- name of / path to your file

with open(filepath, 'r') as f: fLines = f.read().splitlines() #<-- read file
kCur = '__no_parent_key__' #<-- set a default for if 1st line isn't a [key]
result = {kCur: {}} #<-- initiate

for l in fLines:
    if '=' in l: _, l = result[kCur].update([l.split('=', 1)]), ''# [l empty -> skip]

    l = l.strip()
    if not l: continue #<-- skip empty lines

    kCur = l[1:-1] if (l[0], l[-1]) == ('[', ']') else l #<-- trim [] 
    result.setdefault(kCur, {})

# remove '__no_parent_key__' if empty:
if not result['__no_parent_key__']: del result['__no_parent_key__']

对于示例代码段,result将如下所示

{ 
  'ThisShouldBeAKey': {'Value1': 'yes', 'Value2': 'no', 'Value3': 'fancywords', 'Value4': 'numbers'},
  'ThisShouldBeAnotherKey': {'Value2': 'true', 'Value3': '333', 'Value5': 'qqq'} 
}

您还可以使用参考字典(如下面的kwList)和ast.literal_eval来进一步解析值。

kwList = {'true':True, 'false':False, 'null': None, 'none': None}
def try_eval(literalStr:str, kwRef=kwList):
    if literalStr.strip().lower() in kwRef: 
        return kwRef[literalStr.strip().lower()]
    try: return ast.literal_eval(literalStr)
    except: return literalStr

要使用try_eval,请将我建议的解决方案中的 if '=' in l:.. 块更改为

if '=' in l: 
        k, v = l.split('=', 1) 
        result[kCur][k] = try_eval(v)
        continue

那么result看起来就像

{ 
  'ThisShouldBeAKey': {'Value1': 'yes', 'Value2': 'no', 'Value3': 'fancywords', 'Value4': 'numbers'},
  'ThisShouldBeAnotherKey': {'Value2': True, 'Value3': 333, 'Value5': 'qqq'} 
}

[Note ThisShouldBeAnotherKeyValue2Value3的变化。]

相关问题