0

以前,我想创建一个简单的字符串OrderedDict转换为json输出。
实际上我们可以只使用json.dumpswhen 它输入 as OrderedDict,例如:

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

但问题是它输入为 a stringof OrderedDictstringlist ofOrderedDict或 mybe 只是stringdict/list 的一个。它还应该支持递归值、字节输入{b'a': 1}和 unicode {u'a': 1}

在这里,我没有使用eval,因为Eval 使用起来真的很危险

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

类型 1,单个字符串OrderedDict

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

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

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

类型 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,使用unicodeor bytes

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

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

2 回答 2

4

也许有更接近您的问题的解决方案。据我所知,您可以使用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}
于 2021-08-24T01:31:56.357 回答
0

您可以使用解析器。

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

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, TEXT( })

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

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

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

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

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) 数据('abc', 1), RPAREN, TEXT(]), RPAREN, TEXT(})

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

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

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

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

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

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

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

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

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)
于 2021-08-24T03:32:31.627 回答