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

Convert ugly string (custom non-json format) to dictionary

我有这个字符串,我想将其作为字典加载,以便我可以访问每一项。

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

目前我正在使用正则表达式(re library)来获取字符串中任何项目的值,这很有效。

有没有更简洁的方法将这个字符串转换成字典?我试过 json.loads()ast 都不起作用。

预期结果:

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

我同意你的看法,通常 json.loads() 将是摄取它的首选。该字符串从何而来?

正确的解决方案

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

骇人听闻的解决方案

肯定一些结构留在那里, 在标点符号和行尾之间, 所以在最坏的情况下,你值得花时间破解一个 UnStrip 放回丢失的引号的例程。 在例如的情况下b=123, 发射 'b':'123' 也不会太糟糕, 正如您始终可以 post 处理的那样, 您递归地尝试将字典值转换为数字的地方, 如果值结果为 try / except 则忽略错误 看起来更像 'xyz' 而不是某个整数。

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

好吧,这很难看,但它可以为您提供一个创建更有效解决方案的起点。基本上,与第一个替换的一系列替换包括切片和用 dict 闭包替换左括号和右括号。然后,ast.literal_eval转换为dict。

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'"', a)
c = re.sub(r'([^{}[\]:,])([{}[\]:,])', r'"', 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
  • 稍微宽容一些