1

我知道这个问题听起来是重复的,但事实并非如此,至少看了一段时间,对于我的具体问题,我什么也做不了。

我有以下字符串:

"{first : {name : 'test', value : 100}, second : {name : 'test2', value : 50}}"

我想将该字符串转换为字典,如下所示:

{'first': {'name': 'test', 'value' : 100}, 'second': {'name': 'test2', 'value' : 50}}

有任何想法吗?我正在使用 Python 2.5

谢谢

4

2 回答 2

6

首先,如果您从字典(使用 Python 或几乎任何其他语言)生成这些字符串,您可能需要考虑以易于解析的方式生成它们。例如,在 Python 中。要么 要么repr(d)会给json.dumps(d)你一些与现有字符串非常相似的东西,但带有适当的引号。


但是如果你刚刚得到了别人给你的一堆字符串,最简单的方法可能是将它正则表达式转换为一个实际的 JSON 字符串,以便你可以解析它:

json.loads(re.sub(r",\s*(\w+)", r", '\1'", 
                  re.sub(r"\s*\{\s*(\w+)", r"{'\1'", x)).replace("'", '"'))

在 2.5 中,没有内置json模块,所以你可能想要pip install simplejson然后你可以这样做:

try:
  import json
except ImportError:
  import simplejson as json

(或者,当然,simplejson如果您愿意,您可以无条件地要求。)


另一种选择是使用ast.literal_eval而不是json.loads. 哪个合适取决于有关您的字符串的更多信息。JSON 比 Python 语法更受限制,因此如果您担心输入的来源,它会更安全,但如果您的输入可能合法地包含 JSON 无法处理的内容(例如1+3j.

json但是,likeast是 2.6 的新内容,并且 PyPI 上没有可用的替代品。幸运的是,2.5确实有这个_ast模块,你可以literal_eval从 2.6复制并粘贴源代码ast.py,但这有点麻烦。ActiveState 也有一些食谱,例如http://code.activestate.com/recipes/364469/,虽然与 不同literal_eval,但可能适合您的目的。

这仍然行不通,因为您还缺少示例字符串中的右大括号。我希望这是一个错字,在这种情况下没有问题。

如果不是,您需要解释您希望它对此类情况实际执行的操作。也许自动关闭任何未闭合的大括号?如果是这样,未闭合的括号也会是一个问题吗?

于 2012-11-08T21:06:14.087 回答
1

您可以尝试使用向后兼容 Python 2.5 的pyparsing - 请参阅下面带注释的代码中的注释:

from pyparsing import Suppress, Forward, Word, nums, quotedString, removeQuotes, alphas, alphanums, Group, delimitedList

# define some punctuation expressions
LBRACE,RBRACE,COLON = map(Suppress,"{}:")

# forward declare dict_, because we will use it as part of defining
# dict_value, which we will then use to define dict_ (i.e., the grammar
# is recursive)
dict_ = Forward()

# what does a key value look like (guessing it is any word that
# starts with an alpha or '_', followed by zero or more alphas, nums, or '_'s)
dict_key = Word(alphas+'_',alphanums+'_')

# define possible values for dict entries (expand as needed)
# parse actions do data conversion during parsing, so that we get native Python types,
# not just strings for everything that we have to convert later
integer = Word(nums).setParseAction(lambda t:int(t[0]))
quotedString.setParseAction(removeQuotes)
dict_value = quotedString | integer | dict_

# a dict element is key : value
dict_element = Group(dict_key + COLON + dict_value)

# use a parse action to convert parsed data to dicts while parsing
make_dict = lambda t: dict(t.asList())

# finally, define dict_ using '<<' operator to "inject" the pattern into the previously
# defined Forward - delimitedList(expr) is a short-cut for expr + ZeroOrMore(',' + expr)
dict_ << (LBRACE + (delimitedList(dict_element).setParseAction(make_dict) + RBRACE))

# parse the input string - we get back a real dict, not just a hierarchical list of strings
data = "{first : {name : 'test', value : 100}, second : {name : 'test2', value : 50}}"
dd = dict_.parseString(data)[0]
print type(dd)
print dd
print dd.keys()
print dd['first'].keys()

印刷:

<type 'dict'>
{'second': {'name': 'test2', 'value': 50}, 'first': {'name': 'test', 'value': 100}}
['second', 'first']
['name', 'value']
于 2012-11-09T00:59:04.450 回答