Python - 用字符串制作一个字典

时间:2015-02-24 05:22:05

标签: python string dictionary

我有一个这样的字符串:

home_id: [redacted] id: [7] name: [] model: []

我希望将其转换为dict,例如home_id是关键,redactedwithout the braces)是值,依此类推。我可以通过替换和拆分以及十几行来完成这项工作,但似乎可能有一种更简单的方法。如果你想知道,这是一个由openzwave中的louie调度返回的字符串,我看,我找不到一种方法来获得预先分解的值。

是的,我已经搜索过类似问题的StackOverflow,但大多数格式都是这样的,即文字或JSON可以做到这一点,或者它的方式是空格是一个更好的分隔符(在我的情况下,一个空格分隔两者来自值的对和键)。而且我不是正则表达式,所以我宁愿避免它。感谢。

5 个答案:

答案 0 :(得分:4)

不使用re:

s = 'home_id: [redacted] id: [7] name: [] model: []'
d = dict([pair.strip().split(': [') for pair in s.split(']') if pair])

假设您的值和键不包含字符串']',因此它的唯一外观将是分隔符。从好的方面来说,带空格的值不会使它跳起来。

答案 1 :(得分:3)

import re
x="home_id: [redacted] id: [7] name: [] model: []"
print dict(re.findall(r"([^: ]*)\s*:\s*\[([^\]]*)\]",x))

试试这个衬垫。

输出:{'home_id': 'redacted', 'model': '', 'id': '7', 'name': ''}

答案 2 :(得分:3)

使用字典理解的非正则表达方式:

>>> s = "home_id: [redacted] id: [7] name: [] model: []"
>>> tokens = s.split()
>>> d = {k.strip(':'):v.strip('[]') for k,v in
             zip(tokens[::2], tokens[1::2])}
>>> d
{'home_id': 'redacted', 'model': '', 'id': '7', 'name': ''}

答案 3 :(得分:1)

如果你被正则表达式吓倒了,并希望随着时间推移可能更具可读性/可维护性的替代方案,那么你可能会考虑使用pyparsing。 Pyparsing比正则表达式更冗长,但您可能会发现结构和编码更容易遵循,这反过来又会使将来更容易回复以进行更改。此外,pyparsing为您提供了一些快捷方式,例如隐式跳过空格,因此您可以专注于定义解析器的重要位,而不必在某些空格可能出现的任何地方撒上\s*

以下是编写一个简短解析器以将输入字符串解析为dict的步骤。

首先导入pyparsing的类和常量定义。我们还将使用一个新功能在我们的解析器定义中使用文字字符串,但是将它们从输出中抑制 - 对于在解析过程中很重要的标点符号这样的东西很有用,但通常只会妨碍它。

from pyparsing import *
ParserElement.inlineLiteralsUsing(Suppress)

接下来,我们将使用pyparsing的Word和QuotedString类来定义输入dict中每个元素的键和值部分的表达式。 alphasalphanums是在pyparsing中定义的字符串,包含您期望的内容:alphas是一个包含所有大写和小写字母字符的字符串,alphanums是相同的字符串加上10位数字。使用Word类,我们指定我们希望我们的键表达式是一个连续的字符集,从任何alpha开始,然后是零个或多个alphanums或' _' s。值表达式使用pyparsing的QuotedString类,允许您指定开始和结束引用字符。 QuotedString有一些额外的运行时行为,例如支持' \'如果某个值必须包含']'字符,并从最后的字符串中删除封闭的' []'

key_expr = Word(alphas, alphanums+'_')
value_expr = QuotedString('[',endQuoteChar=']')

鉴于这些基本元素,我们可以定义单个键值对的外观,这是一个键,一个':'和一个值。 Pyparsing overpides' +'运算符表示我们正在从这些简单的键和值原语构建更大的表达式。 (分隔的':'字符将从解析的结果中被抑制,因为我们在上面指出任何内联的文字将使用pyparsing Suppress类添加到表达式。)

Pyparsing还默认将所有已解析的字符串作为已解析元素的平面列表返回。为了维护键值结构,我们可以将键值对括在一个pyparsing Group中:

key_value_pair = Group(key_expr + ':' + value_expr)

最后,您的表达式包含一个或多个此类键值对,因此我们使用pyparsing的OneOrMore类来表示:

parser = OneOrMore(key_value_pair)

使用此解析器,让我们针对您的输入字符串运行它:

source = "home_id: [redacted] id: [7] name: [] model: []"
results = parser.parseString(source, parseAll=True)

Pyparsing返回ParseResults对象中的已解析数据,该对象具有非常丰富的解析后API。可以访问解析的值,就好像数据只是作为列表返回一样,或者如果在解析器定义期间指定了键,则可以通过键值访问。或者我们可以使用ParseResults'将结果看作实际的Python列表。 asList()方法:

print results.asList()

给出:

[['home_id', 'redacted'], ['id', '7'], ['name', ''], ['model', '']]

如果你对Python有初学者知识,你知道你可以将这种列表作为构造函数参数传递给dict类,并获得一个带有' home_id',&#键的字典。 39; id'等等和相应的值。

print dict(results.asList())

给出:

{'home_id': 'redacted', 'model': '', 'id': '7', 'name': ''}

这应该足以让你开始使用pyparsing。但是还有一个稍微更高级的步骤,让pyparsing定义这些键和值作为解析过程的一部分。正如Pyparsing定义Group为返回结果添加结构一样,pyparsing还定义了Dict类以添加数据的分析时解释,将每个组的第一个元素作为键,并将每个组的其余元素作为值,并使用输入字符串中的值动态定义结果名称。我们只需将先前定义的解析器包装在pyparsing Dict中:

parser = Dict(OneOrMore(key_value_pair))

现在不要将结果显示为列表,而是使用ParseResults'方法dump()以列表和密钥形式列出标记:

results = parser.parseString(source)
print results.dump()

给出:

[['home_id', 'redacted'], ['id', '7'], ['name', ''], ['model', '']]
- home_id: redacted
- id: 7
- model: 
- name:

也就是说,第一行以列表形式显示已解析的值,然后是用于访问各个已解析字段的可用结果名称的项目符号列表。

正如我们之前使用asList()获取标准Python列表中的值一样,ParseResults类也有一个asDict()方法来将数据作为标准Python字典返回:

print results.asDict()

给出:

{'home_id': 'redacted', 'model': '', 'id': '7', 'name': ''}

以下是完整的示例:

source = "home_id: [redacted] id: [7] name: [] model: []"


from pyparsing import *
ParserElement.inlineLiteralsUsing(Suppress)

key_string = Word(alphas, alphanums+'_')
value = QuotedString('[',endQuoteChar=']')

key_value_pair = Group(key_string + ':' + value)
parser = OneOrMore(key_value_pair)

results = parser.parseString(source)

print results.asList()
print dict(results.asList())

# alternative form
parser = Dict(OneOrMore(key_value_pair))

results = parser.parseString(source)

print results.dump()
print results.asDict()

答案 4 :(得分:1)

另一种正则表达式解决方案。

>>> s = 'home_id: [redacted] id: [7] name: [] model: []'
>>> dict([x.rstrip(']').split(': [') for x in re.split(r'\s+(?=\w+:)', s)])
{'name': '', 'id': '7', 'home_id': 'redacted', 'model': ''}