Python:如何将字符串解析为递归字典

Python:如何将字符串解析为递归字典,python,python-2.7,Python,Python 2.7,来自一个文件,我有如下字符串: var1 : data1 var2 : data2 dict1 { var3 : data3 dict2 { var4 : data4 } var5 : data5 } dict3 { var6 : data6 var7 : data7 } 等等。(行尾为\n,每行\t为缩进) 我试着把它转换成这样: Dictionary={"var1":"data1","var2":

来自一个文件,我有如下字符串:

var1 : data1
var2 : data2
dict1 {  
     var3 : data3  
     dict2 {  
         var4 : data4  
     }
     var5 : data5
}
dict3 {
     var6 : data6
     var7 : data7
}
等等。(行尾为\n,每行\t为缩进)
我试着把它转换成这样:

Dictionary={"var1":"data1","var2":"data2", "dict1" : 
    {"var3":"data3", "dict2" : {
        "var4":"data4" }, "var5":"data5"}
    , dict3:{"var6":"data6","var7":"data7"}
(缩进非常容易让人阅读)
为了解决这个问题,我所能想到的就是将它拆分成一个列表,然后向下遍历列表,直到我在字符串中找到一个“}”,删除它(这样我以后就不会碰到它),然后向上遍历,直到我找到带有“{”的字符串,删除前面的空格和后面的“{”(立即使用
temp=re.split(“(\S+)\{',out[z])
对于这个例子,第一个temp[1]将是'dict2'),添加中间的所有内容,最后转到下一个“}”

但这既不快速也不优雅。我肯定错过了一些东西。
代码当前为:

def procvar(strinG):
    x=y=z=temp1=temp2=0
    back = False
    out=re.split ('\n',strinG) #left over from some other tries
    while z < len(out):
        print "z=",z," out[z]= ", out[z]
        if "{" in out[z]:
            if back == True:
                back = False
                xtemp=re.split ('(\S+) \{',out[z])
                out[z]=xtemp[1]
                ytemp=xtemp[1]
                temp2=z+1
                print "Temp: ",temp1," - ",out[temp1]
                out[z]={out[z]:[]}
                while temp2 <= temp1:
                    out[z][xtemp[1]].append(out[temp2]) # not finished here, for the time being I insert the strings as they are
                    del out[temp2]
                    temp1-=1
                print out[z]
        if "}" in out[z]:
            back = True
            del out[z]
            temp1 = z-1
        if back == True:
            z-=1
        else:
            z+=1
    return out
def procvar(字符串):
x=y=z=temp1=temp2=0
返回=错误
out=re.split('\n',strinG)#从其他尝试中遗留下来的
当z虽然temp2您的格式与yaml格式非常接近(易于安装pyyaml):

重新导入
#关键字:value regexp
KV_RE=RE.compile(r'^\s*(?P[^\s]+)\s+:\s+(?P.+?)\s*$)
#dict start regexp
DS_RE=RE.compile(r'^\s*(?P[^\s]+)\s+{\s*$)
#dict end regexp
DE_RE=RE.compile(r'^\s*}\s*$)
def解析:
当前={}
堆栈=[]
对于s.strip()中的线。splitlines():
匹配=千伏匹配(线路)
如果匹配:
gd=match.groupdict()
当前[gd['key']]=gd['value']
持续
match=DS_RE.match(行)
如果匹配:
stack.append(当前)
current=current.setdefault(match.groupdict()['key'],{})
持续
匹配=重新匹配(行)
如果匹配:
当前=stack.pop()
持续
#发生错误
打印('错误:%s'%1行)
返回{}
回流

如果文本的规则模式与示例相同,则可以使用解析字符串

首先,让我们将字符串修改为合法的Python dict文本:

import re

st='''\
var1 : data1
var2 : data2
dict1 {  
     var3 : data3  
     dict2 {  
         var4 : data4  
     }
     var5 : data5
}
'''

# add commas after key, val pairs
st=re.sub(r'^(\s*\w+\s*:\s*\w+)\s*$',r'\1,',st,flags=re.M)

# insert colon after name and before opening brace 
st=re.sub(r'^\s*(\w+\s*){\s*$',r'\1:{',st,flags=re.M)

# add comma closing brace
st=re.sub(r'^(\s*})\s*$',r'\1,',st,flags=re.M)

# put names into quotes
st=''.join(['"{}"'.format(s.group(0)) if re.search(r'\w+',s.group(0)) else s.group(0) 
                for s in re.finditer(r'\w+|\W+',st)])

# add opening and closing braces
st='{'+st+'}'
print st
打印修改后的字符串:

{"var1" : "data1",
"var2" : "data2",
"dict1" :{
     "var3" : "data3",
"dict2" :{
         "var4" : "data4",
     },
     "var5" : "data5",
},}
现在使用ast将字符串转换为数据结构:

import ast
print ast.literal_eval(st)
印刷品

{'dict1': {'var5': 'data5', 'var3': 'data3', 'dict2': {'var4': 'data4'}}, 'var1': 'data1', 'var2': 'data2'}

此解决方案的唯一问题是,如果键和值包含
{
}
字符,它将修改它们。这是一个黑客攻击。正确的解决方案是适应Yaml的语言,它似乎可行,但我对它了解不够:可能只是修复替换:
x=re.sub('^\s*}\s*$,'',x)
x=re.sub('^(\s*[^\s]+\s+{(\s*)$,'\\1:\\2',x)
。这样会安全一点。嗯,也不错。也许我也尝试一下。因为字符串不是用石头写的。事实上,我是在某个时候生成的。我想我可能必须实现某种方法,使数据字符串能够处理多行。如果你能控制程序的创建对于这些文件,有更好的持久数据选项。看看并感谢大家,认为处理regexp的正确方法就是一切,嗯?事实上,我不得不做一些轻微的修改,比如
KV_RE=RE.compile('^\s*(?P[\w\d]+):(?P.*)”
由于数据字符串可能包含数据,也可能不包含数据,或者可能不包含空格和类似内容。此外,由于某些原因,函数有时会遇到空堆栈。为了防止此函数崩溃,我使用了
try:
。这只是一个粗略的近似值,因为我不知道您的dat如何a完全像。如果它确实是规则的,没有特殊字符,那么yaml和literal_eval解决方案也是一个不错的选择,它更通用、更可扩展。但是如果出现空堆栈错误,这可能意味着数据毕竟不是那么规则?或者不是每个右大括号都在自己的行上?
import ast
print ast.literal_eval(st)
{'dict1': {'var5': 'data5', 'var3': 'data3', 'dict2': {'var4': 'data4'}}, 'var1': 'data1', 'var2': 'data2'}