将Valve数据结构转换为JSON

时间:2019-12-02 16:11:02

标签: python json

我有一个看起来与JSON非常相似的数据结构:

"items"
{
    "first"
    {
        "a"     "1"
        "b"     "2"
        "c"     "3"
        "d"     "4"
        "e"     "5"
    }
    "second"
    {
        "f"     "6"
        "g"     "7"
        "h"     "8"
        "i"     "9"
        "j"     "10"
    }
}

但是问题是这种格式不适用于JSON解析器。 Python中是否有任何方法可以将这种格式转换为JSON格式来管理我的数据?我尝试使用json.loads(json.dumps(data)),但是它不起作用。当使用jsonObj['items']来搜索这种格式的数据时,它将显示TypeError: string indices must be integers

我的目标是按照以下原则进行操作:

"items" :
{
    "first" :
    {
        "a" : "1",
        "b" : "2",
        "c" : "3",
        "d" : "4",
        "e" : "5"
    },
    "second" :
    {
        "f" : "6",
        "g" : "7",
        "h" : "8",
        "i" : "9",
        "j" : "10"
    }
}

3 个答案:

答案 0 :(得分:1)

幸运的是,the format使用的原子与Python足够相似,我们可以将tokenizeast模块用于即席解析器。

输入断开时,它可能会严重损坏,但适用于您的示例数据:)

import tokenize
import token
import ast
import io
import json


def parse_valve_format(data):
    dest = {}
    stack = [dest]
    for tok in tokenize.tokenize(io.BytesIO(data.encode()).readline):
        if tok.type == token.STRING:
            ts = ast.literal_eval(tok.string)
            if isinstance(stack[-1], str):
                # already a string on the stack?
                # this has to be a key-value setting
                key = stack.pop(-1)
                stack[-1][key] = ts
            else:
                # otherwise assume we'll find a } soon
                stack.append(ts)
        elif tok.type == token.OP and tok.string == "{":
            obj = {}
            key = stack.pop(-1)
            stack[-1][key] = obj
            stack.append(obj)
        elif tok.type == token.OP and tok.string == "}":
            assert isinstance(stack[-1], dict), "stray }"
            stack.pop(-1)
    return dest


result_dict = parse_valve_format(
    """
"items"
{
    "first"
    {
        "a"     "1"
        "b"     "2"
        "c"     "3"
        "d"     "4"
        "e"     "5"
    }
    "second"
    {
        "f"     "6"
        "g"     "7"
        "h"     "8"
        "i"     "9"
        "j"     "10"
    }
}
"""
)

print(json.dumps(result_dict, indent=2))

输出:

{
  "items": {
    "first": {
      "a": "1",
      "b": "2",
      "c": "3",
      "d": "4",
      "e": "5"
    },
    "second": {
      "f": "6",
      "g": "7",
      "h": "8",
      "i": "9",
      "j": "10"
    }
  }
}

答案 1 :(得分:0)

这不是JSON数据。

JSON数据的格式

{
   "foo" : "bar"
   "sample2": {
                 "key1: value
              }
}

您的数据不是以这种方式存储的,至少不是以JSON格式存储的,因此JSON Parse函数将不起作用。

现在进入JSON分析器,它有时可以针对缺少的键或值进行更正,但是在您的情况下,它看起来好像不了解发生了什么。

您最好的选择是使用Regex Magic一点点将其转换为JSON格式并从那里开始。

答案 2 :(得分:0)

您可以滚动自己的解析器/编译器。这是一个仅适用于您给出的示例的示例。 (例如,不适用于包含空格或列表/数字/等的令牌。)

def match_str(s):
    return len(s) >= 2 and s[0] == '"' and s[-1] == '"'

def match_terminal(s):
    return s == "{" or s == "}"

def notjsonstr_to_jsonstr(s):
    tokens = s.split()
    xs = []
    was_terminal = True
    was_str = False

    for token in tokens:
        if len(xs) != 0 and xs[-1] == "}" and token != "}":
            xs.append(",")
        if match_terminal(token):
            if was_str:
                xs.append(":")
            xs.append(token)
            was_terminal = True
            was_str = False
            continue
        if match_str(token):
            if was_str:
                xs.append(":")
            elif not was_terminal:
                xs.append(",")
            xs.append(token)
            was_str = not was_str
        else:
            raise Exception("Unexpected token")
        was_terminal = False

    return "".join(xs)

这当然是非常有缺陷的,只能在非常有限的语法下使用,并且可能会使任何解析器编写者皱鼻子。