在 Python 中将 OrderedDict 的字符串转换为 JSON

Posted

技术标签:

【中文标题】在 Python 中将 OrderedDict 的字符串转换为 JSON【英文标题】:Convert String of OrderedDict to JSON in Python 【发布时间】: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 表单(就像这个评论表单一样),但实际上我们的后端代码,我们会得到它的值作为字符串,对吧? 嗯……那是个什么样的网站? 【参考方案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)

【讨论】:

以上是关于在 Python 中将 OrderedDict 的字符串转换为 JSON的主要内容,如果未能解决你的问题,请参考以下文章

如何在 python 中添加一个 OrderedDict()

python之OrderedDict类

在 Python 3 中获取“OrderedDict”第一项的最短方法

OrderedDict如何在Python中保持秩序

Python中的OrderedDict

在 python2.6 中应该使用 OrderedDict 的哪个实现?