将丑陋的字符串(自定义非json格式)转换为字典

时间:2019-04-18 02:25:40

标签: python python-3.x dictionary string-conversion

我有一个要作为字典加载的字符串,以便可以访问每个项目。

my_str = "[
    id=xyz-111,
    abc= {
            item=[
                    {
                        a=xyz,
                        b=123,
                        c={},
                        d={
                        i=[{ip=0.0.0.0/0}]
                            },
                    }
            ]
    }
]"

当前,我正在使用正则表达式(re库)来获取字符串中任何项目的值,这是可行的。

有没有更清洁的方法将此字符串转换为字典?我尝试过json.loads()ast无效。

预期结果:

my_dict = {
    'id':'xyz-111',
    'abc': {
            'item':[
                    {
                        'a':'xyz',
                        'b':123,
                        'c':{},
                        'd':{
                        'i':[{'ip':'0.0.0.0/0'}]
                            },
                    }
            ]
    }
}

2 个答案:

答案 0 :(得分:3)

嗯,这很丑陋,但它可能为您提供一个起点,从那里可以创建更有效的解决方案。基本上,第一个替换是一系列替换,包括切片和用dict封闭替换开合括号。然后,ast.literal_eval转换为字典。

import ast
import re

s = """
[
    id=xyz-111,
    abc= {
      item=[
        {
          a=xyz,
          b=123,
          c={},
          d={
            i=[{ip=0.0.0.0/0}]
          },
        }
      ]
    }
]
"""

a = '{' + re.sub(r'=', r':', re.sub(r'\s+', '', s))[1:-1] + '}'
b = re.sub(r'([{}[\]:,])([^{}[\]:,])', r'\1"\2', a)
c = re.sub(r'([^{}[\]:,])([{}[\]:,])', r'\1"\2', b)
d = ast.literal_eval(c)

print(d)
# {'id': 'xyz-111', 'abc': {'item': [{'a': 'xyz', 'b': '123', 'c': {}, 'd': {'i': [{'ip': '0.0.0.0/0'}]}}]}}
  • a删除所有空白,将=替换为:,并将外部[]替换为{}(空白删除是一种钝器,需要使用如果数据中包含需要保留空格的字符串,则可以更具体地定位目标
  • b"插入方括号,分号或逗号后,再不插入任何这些字符
  • c在括号,分号或逗号之前插入",这些字符中没有任何一个
  • d使用ast.literal_eval将字符串转换为字典,比json.loads宽容得多

答案 1 :(得分:0)

我同意您的看法,通常json.loads()是摄取该内容的首选。那个字符串是从哪里来的?

正确的解决方案

似乎某些代码的layer_1生成了格式正确的JSON, 然后layer_2删除引号。 找到layer_2,并告诉它停止这样做。 或者,复制layer_2, 有自己的代码使用原始输入 并更好地处理它, 这样报价就不会丢失。

骇客解决方案

肯定还有 那里还有一些结构, 在标点和行尾之间 因此在最坏的情况下,值得您花一点时间一起破解UnStrip 例行程序将丢失的引号放回去。 在例如b=123,发出'b':'123'并不坏, 您可以随时发布流程, 在其中递归地尝试将字典值转换为数字, try / except时忽略错误 看起来更像'xyz',而不是整数。

实际上,将n = float(s)包装在try中的示例是有启发性的。 在输入的任何给定行中可能会有一些歧义, 并可以选择将变体A或B用作有效JSON。 尝试将两者都包裹在try中可能很有用, 然后返回第一个获胜的 第一个评估为有效JSON的人。