【问题标题】:Convert String of OrderedDict to JSON in Python在 Python 中将 OrderedDict 的字符串转换为 JSON
【发布时间】:2021-10-24 06:43:30
【问题描述】:

以前,我想创建一个简单的字符串OrderedDict 转换为json 输出。
其实我们可以直接用json.dumps输入OrderedDict,例如:

>>> json.dumps([OrderedDict([('abc', 1)])])
'[{"abc": 1}]'
>>>

但问题是它输入为OrderedDictstringOrderedDictstring 列表或mybe 只是dict/list 的string它还应该支持递归值、字节输入 {b'a': 1} 和 unicode {u'a': 1}

在这里,我没有使用eval,因为Eval is really dangerous to use

以下是一些示例输入和预期输出:

类型1,单个字符串OrderedDict

input = "OrderedDict({'abc': 1})"
output = {"abc": 1}

类型 2,带有递归值的单个字符串 OrderedDict

input = "OrderedDict([('abc', OrderedDict([('def', 2)]))])"
output = {"abc": {"def": 2}}

Type 3,一个字符串dict,单个值为OrderedDict

input = "{'key': OrderedDict([('abc', 1)])}"
output = {"key": {"abc": 1}}

类型 4,带有OrderedDict 值的字符串列表:

input = "[OrderedDict([('abc', 1)])]"
output = [{"abc": 1}]

类型 5,只是一个字符串字典:

input = "{'abc': 1}"
output = {"abc": 1}

类型6,只是一串列表:

input = "[{'abc': 1}]"
output = [{"abc": 1}]

类型 7,使用 unicodebytes

input = "{u'abc': 1}"
output = {"abc": 1}

input = "{b'abc': 1}"
output = {"abc": 1}

【问题讨论】:

  • 为什么会有这样的字符串?
  • @KellyBundy 因为输入来自 html form。所以给定的输入可以有不同的格式。
  • 你的意思是用户输入了那个字符串?或者它是由某些框架/代码生成的,可能不应该这样做?
  • @KellyBundy 所以,基本上用户会将他确切的OrderedDict 代码放入 html 表单(就像这个评论表单一样),但实际上我们的后端代码,我们会得到它的值作为字符串,对吧?
  • 嗯……那是个什么样的网站?

标签: python json python-3.x ordereddict


【解决方案1】:

也许有更接近您的问题的解决方案。据我所知,您可以使用ast.literal_eval,但您需要手动将 2 项元组转换为 dict。

import ast

for the_input in [
    "OrderedDict({'abc': 1})",
    "OrderedDict([('abc', OrderedDict([('def', 2)]))])",
    "{'key': OrderedDict([('abc', 1)])}",
    "[OrderedDict([('abc', 1)])]",
    "{'abc': 1}",
    "[{'abc': 1}]",
    "{u'abc': 1}",
    "{b'abc': 1}",
]:
    the_input = the_input.replace("OrderedDict", "")
    the_output = ast.literal_eval(the_input)
    print(type(the_output), the_output)

输出

<class 'dict'> {'abc': 1}
<class 'list'> [('abc', [('def', 2)])]
<class 'dict'> {'key': [('abc', 1)]}
<class 'list'> [[('abc', 1)]]
<class 'dict'> {'abc': 1}
<class 'list'> [{'abc': 1}]
<class 'dict'> {'abc': 1}
<class 'dict'> {b'abc': 1}

【讨论】:

    【解决方案2】:

    您可以使用解析器。

    这显然不是一个简单的解决方案,但如果您已经熟悉解析,则绝对可以在这里应用。

    现有的 Python 解析器有很多不同的,例如,假设您选择 PLY(不是最好的,但考虑到您想要做的就足够了)

    解析首先需要对文本进行标记。在这里你只需要几个令牌:

    import ply.lex as lex
    
    tokens = (LPAREN, RPAREN, ORDEREDDICT, TEXT)
    t_LPAREN = "("
    t_RPAREN = ")"
    t_ORDEREDDICT = "OrderedDict"
    t_TEXT = r'(?:(?!(OrderedDict|\(|\))).)+'
    
    lexer = lex.lex()
    

    这意味着解析器将认为“(”符号是“LPAREN”(左括号),“)”符号是“RPAREN”,而序列“OrderedDict”是一个特殊的东西。其他符号序列(不包含括号或“OrderedDict”序列)将被视为 TEXT。

    例如,"{'key': OrderedDict([('abc', 1)])}" 此时将转换为: TEXT({'key': ), ORDEREDDICT, LPAREN, TEXT([), LPAREN, TEXT('abc', 1), RPAREN, TEXT(]), RPAREN, TEXT(}) 您可以使用以下方法对其进行测试:

    lexer.input("{'key': OrderedDict([('abc', 1)])}")
    

    然后可以进行实际的解析:

    import ply.yacc as yacc
    import json
    
    def p_ordereddict(p):
        'data : ORDEREDDICT LPAREN data RPAREN'
        p[0] = json.dumps(OrderedDict(json.loads(p[3])))
    
    def p_otherparenthesis(p):
        'data : LPAREN data RPAREN'
        p[0] = p[1]+p[2]+p[3]
    
    def p_concat(p):
        'data : data data'
        p[0] = p[1]+p[2]
    
    def p_texttodata(p):
        'data : TEXT'
        p[0] = p[1]
    
    parser = yacc.yacc()
    

    这应该被理解为三个规则:

    • 如果我看到“ORDEREDDICT”标记,我必须在其后查找左括号,然后是称为“数据”的内容,然后是右右括号。然后将整个事物本身视为“数据”,其值是我们在括号之间但通过“OrderedDict”运算符传递的数据之一。
    • 如果我看到一个左括号(而我不是在前一种情况下),我需要识别一个“数据”序列和一个右右括号。整个事情本身就是数据。
    • 如果我看到多个数据彼此相邻,我可以将它们连接起来
    • 标记为 TEXT 的内容是数据

    收回我们之前的例子:

    "{'key': OrderedDict([('abc', 1)])}"

    被转换为:

    TEXT({'key': ), ORDEREDDICT, LPAREN, TEXT([), LPAREN, TEXT('abc', 1), RPAREN, TEXT(]), RPAREN, TEXT(})

    解析器从左边开始,找到一个 TEXT 标记。唯一关心前导 TEXT 令牌的规则是第 4 条,根据这条规则,令牌变成数据:

    data({'key': ), ORDEREDDICT, LPAREN, TEXT([), LPAREN, TEXT('abc', 1), RPAREN, TEXT(]), RPAREN, TEXT(})

    现在我们有了一个领先的数据对象。定义应该发生什么的规则是第三条:我们必须进一步寻找其他数据对象:

    data({'key': ), (我们现在在这里,寻找数据) ORDEREDDICT, LPAREN, TEXT([), LPAREN, TEXT('abc', 1), RPAREN, TEXT(]), RPAREN , 文本(})

    ORDEREDDICT 令牌由第一条规则处理,因此变为:

    data({'key': ), (我们期望这里有数据) ORDEREDDICT, LPAREN, (我们在这里, 寻找数据然后RPAREN) TEXT([), LPAREN, TEXT('abc', 1), RPAREN, TEXT(]), RPAREN, TEXT(})

    然后,根据第 4 条规则将 TEXT([) 识别为数据:

    data({'key': ), (我们期望这里有数据) ORDEREDDICT, LPAREN, (我们在这里, 寻找数据然后RPAREN) data([), LPAREN, TEXT('abc', 1), RPAREN, TEXT(]), RPAREN, TEXT(})

    data([) 后面的不是 RPAREN,但这不是问题,因为第三条规则意味着可以连接一系列数据对象:

    data({'key': ), (我们在这里期待数据) ORDEREDDICT, LPAREN, (我们期待数据然后在这里 RPAREN) data([), (我们在这里, 寻找数据) LPAREN, TEXT(' abc', 1), RPAREN, TEXT(]), RPAREN, TEXT(})

    第二条规则适用:

    data({'key': ), (我们在这里期待数据) ORDEREDDICT, LPAREN, (我们在这里期待数据然后是 RPAREN) data([), (我们在这里期待数据) LPAREN, (我们在这里, 寻找对于数据,然后是 RPAREN) TEXT('abc', 1), RPAREN, TEXT(]), RPAREN, TEXT(})

    第四条规则:

    data({'key': ), (我们在这里期待数据) ORDEREDDICT, LPAREN, (我们在这里期待数据然后是 RPAREN) data([), (我们在这里期待数据) LPAREN, (我们在这里, 寻找对于数据,然后是 RPAREN) data('abc', 1), RPAREN, TEXT(]), RPAREN, TEXT(})

    我们有我们正在寻找的数据+RPAREN 序列,所以我们可以用第二条规则来总结它:

    data({'key': ), (我们在这里期待数据) ORDEREDDICT, LPAREN, (我们期待数据然后在这里 RPAREN) data([), (我们在这里, 我们期待数据) data((' abc', 1)), TEXT(]), RPAREN, TEXT(})

    现在我们有了应用第三条规则的数据:

    data({'key': ), (我们在这里期待数据) ORDEREDDICT, LPAREN, (我们在这里, 我们期待数据然后在这里 RPAREN) data([('abc', 1)), TEXT(] ), RPAREN, TEXT(})

    我们还不能应用第一条规则。你应该明白了,所以我从现在开始写步骤:

    data({'key': ), (我们在这里期待数据) ORDEREDDICT, LPAREN, (我们期待数据然后在这里 RPAREN) data([('abc', 1)), (我们在这里, 寻找数据)TEXT(]),RPAREN,TEXT(})

    data({'key': ), (我们在这里期待数据) ORDEREDDICT, LPAREN, (我们期待数据然后在这里 RPAREN) data([('abc', 1)), (我们在这里, 寻找数据)数据(]),RPAREN,文本(})

    data({'key': ), (我们在这里期待数据) ORDEREDDICT, LPAREN, (我们在这里, 我们期待数据然后在这里 RPAREN) data([('abc', 1)]), RPAREN,文本(})

    data({'key': ), (我们在这里,我们期望这里有数据) data({'abc':1}), TEXT(})

    (我们在这里)data({'key': {'abc':1}), TEXT(})

    data({'key': {'abc':1}),(我们在这里,寻找数据)TEXT(})

    data({'key': {'abc':1}),(我们在这里,寻找数据)data(})

    数据({'key': {'abc':1}})


    最后,要使用您的解析器,只需调用它的“parse”方法。例如:

    example = "{'key': OrderedDict([('abc', 1)])}"
    parsed = parser.parse(example, lexer=lexer)
    print(parsed)
    

    【讨论】:

      猜你喜欢
      • 2012-05-16
      • 2016-04-08
      • 1970-01-01
      • 1970-01-01
      • 2019-09-28
      • 2020-11-25
      • 2011-04-20
      • 2013-02-04
      • 2020-04-12
      相关资源
      最近更新 更多