在 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]'
>>>
但问题是它输入为OrderedDict
的string
、OrderedDict
的string
列表或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,使用 unicode
或 bytes
:
input = "u'abc': 1"
output = "abc": 1
input = "b'abc': 1"
output = "abc": 1
【问题讨论】:
为什么会有这样的字符串? @KellyBundy 因为输入来自 htmlform
。所以给定的输入可以有不同的格式。
你的意思是用户输入了那个字符串?或者它是由某些框架/代码生成的,可能不应该这样做?
@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()