Python -- 从字符串中生成字典
Python -- making a dict out of a string
我有这样的字符串:
home_id: [redacted] id: [7] name: [] model: []
我想把它变成一个字典,例如 home_id
是键,redacted
(without the braces
) 是值等等.我可能可以通过替换和拆分以及十几行左右的代码来完成此操作,但似乎可能有更简单的方法。如果你想知道,这是一个由 openzwave 中的 louie dispatch 返回的字符串,我已经看过了,我找不到一种方法来获取预先分解的值。
是的,我已经在 Whosebug 上搜索过类似的问题,但大多数的格式都是 ast literal 或 JSON 可以做到的,或者 space 更好分隔符(在我的例子中,space 将对和键与值分开)。而且我不是正则表达式专家,所以我宁愿避免使用它。谢谢。
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': ''}
不使用 re:
s = 'home_id: [redacted] id: [7] name: [] model: []'
d = dict([pair.strip().split(': [') for pair in s.split(']') if pair])
假设您的值和键不包含字符串“]”,因此它的唯一外观将作为分隔符。从好的方面来说,带空格的值不会造成这种情况。
使用字典理解的非正则表达式方式:
>>> 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': ''}
如果您对正则表达式望而却步,并且想要一个随着时间的推移可能会更多 readable/maintainable 的替代方案,那么您可能会考虑使用 pyparsing。 Pyparsing 比正则表达式更冗长,但您可能会发现结构和编码更容易遵循,这反过来又使将来更容易回来进行更改。此外,pyparsing 为您提供了一些快捷方式,例如隐式跳过空格,因此您可以专注于定义解析器的重要位,而不必在任何可能出现空格的地方添加 \s*
s。
这是编写一个简短的解析器以将输入字符串解析为字典的分步说明。
首先导入 pyparsing 的 class 和常量定义。我们还将使用一个新功能来在我们的解析器定义中使用文字字符串,但将它们从输出中抑制 - 对于标点符号等在解析过程中很重要的东西很有用,但通常只是在之后妨碍。
from pyparsing import *
ParserElement.inlineLiteralsUsing(Suppress)
接下来我们将使用 pyparsing 的 Word 和 QuotedString classes 为输入字典中每个元素的键和值部分定义表达式。 alphas
和 alphanums
是在 pyparsing 中定义的字符串,其中包含您所期望的内容:alphas
是所有大写和小写字母字符的字符串,而 alphanums
是同一个字符串加上10 个数字。使用 Word
class,我们指定我们希望我们的键表达式是一组连续的字符,以任何字母开头,然后是零个或多个字母数字或“_”。值表达式使用 pyparsing 的 QuotedString class,允许您指定开始和结束引号字符。 QuotedString 有一些额外的 运行 时间行为,例如在值必须包含 ']' 字符的情况下支持 '\' 转义,以及从最终字符串中剥离封闭的 '[]'。
key_expr = Word(alphas, alphanums+'_')
value_expr = QuotedString('[',endQuoteChar=']')
根据这些基本元素,我们可以定义单个键值对的外观,即一个键、一个“:”和一个值。 Pyparsing 覆盖 '+' 运算符以指示我们正在从这些简单的键和值基元构建更大的表达式。 (定界的 ':' 字符将从解析的结果中被抑制,因为我们在上面指出任何内联文字都将使用 pyparsing Suppress class 添加到表达式中。)
Pyparsing 还默认 return 将所有已解析的字符串作为已解析元素的平面列表。为了维护键值结构,我们可以将我们的键值对封装在一个 pyparsing 组中:
key_value_pair = Group(key_expr + ':' + value_expr)
最后,您的表达式包含一个或多个这样的键值对,因此我们使用 pyparsing 的 OneOrMore class 来表示:
parser = OneOrMore(key_value_pair)
使用这个解析器,让我们运行根据您的输入字符串:
source = "home_id: [redacted] id: [7] name: [] model: []"
results = parser.parseString(source, parseAll=True)
Pyparsing returns 解析数据在一个ParseResults 对象中,它具有非常丰富的post-解析API。解析后的值可以像数据只是 returned 作为列表一样访问,或者如果在解析器定义期间指定了键,则可以通过键值访问。或者我们可以使用 ParseResults 的 asList() 方法将结果视为实际的 Python 列表:
print results.asList()
给出:
[['home_id', 'redacted'], ['id', '7'], ['name', ''], ['model', '']]
如果你甚至对 Python 有初步了解,你就会知道你可以将这种列表作为构造函数参数传递给字典 class,并得到一个键为 'home_id', 'id', 等对应的值.
print dict(results.asList())
给出:
{'home_id': 'redacted', 'model': '', 'id': '7', 'name': ''}
这应该足以让您开始使用 pyparsing。但是还有一个更高级的步骤,让 pyparsing 将这些键和值定义为解析过程的一部分。正如 Pyparsing 定义 Group 以向 returned 结果添加结构一样,pyparsing 还定义了 Dict class 以添加数据的解析时解释,将每个组的第一个元素作为键,并且每个组的剩余元素作为值,并使用在输入字符串中找到的值动态定义结果名称。我们简单地将我们之前定义的解析器包装在一个 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 class 也有一个 asDict() 方法来 return 你的数据作为标准 Python dict:
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()
另一种正则表达式解决方案。
>>> 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': ''}
我有这样的字符串:
home_id: [redacted] id: [7] name: [] model: []
我想把它变成一个字典,例如 home_id
是键,redacted
(without the braces
) 是值等等.我可能可以通过替换和拆分以及十几行左右的代码来完成此操作,但似乎可能有更简单的方法。如果你想知道,这是一个由 openzwave 中的 louie dispatch 返回的字符串,我已经看过了,我找不到一种方法来获取预先分解的值。
是的,我已经在 Whosebug 上搜索过类似的问题,但大多数的格式都是 ast literal 或 JSON 可以做到的,或者 space 更好分隔符(在我的例子中,space 将对和键与值分开)。而且我不是正则表达式专家,所以我宁愿避免使用它。谢谢。
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': ''}
不使用 re:
s = 'home_id: [redacted] id: [7] name: [] model: []'
d = dict([pair.strip().split(': [') for pair in s.split(']') if pair])
假设您的值和键不包含字符串“]”,因此它的唯一外观将作为分隔符。从好的方面来说,带空格的值不会造成这种情况。
使用字典理解的非正则表达式方式:
>>> 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': ''}
如果您对正则表达式望而却步,并且想要一个随着时间的推移可能会更多 readable/maintainable 的替代方案,那么您可能会考虑使用 pyparsing。 Pyparsing 比正则表达式更冗长,但您可能会发现结构和编码更容易遵循,这反过来又使将来更容易回来进行更改。此外,pyparsing 为您提供了一些快捷方式,例如隐式跳过空格,因此您可以专注于定义解析器的重要位,而不必在任何可能出现空格的地方添加 \s*
s。
这是编写一个简短的解析器以将输入字符串解析为字典的分步说明。
首先导入 pyparsing 的 class 和常量定义。我们还将使用一个新功能来在我们的解析器定义中使用文字字符串,但将它们从输出中抑制 - 对于标点符号等在解析过程中很重要的东西很有用,但通常只是在之后妨碍。
from pyparsing import *
ParserElement.inlineLiteralsUsing(Suppress)
接下来我们将使用 pyparsing 的 Word 和 QuotedString classes 为输入字典中每个元素的键和值部分定义表达式。 alphas
和 alphanums
是在 pyparsing 中定义的字符串,其中包含您所期望的内容:alphas
是所有大写和小写字母字符的字符串,而 alphanums
是同一个字符串加上10 个数字。使用 Word
class,我们指定我们希望我们的键表达式是一组连续的字符,以任何字母开头,然后是零个或多个字母数字或“_”。值表达式使用 pyparsing 的 QuotedString class,允许您指定开始和结束引号字符。 QuotedString 有一些额外的 运行 时间行为,例如在值必须包含 ']' 字符的情况下支持 '\' 转义,以及从最终字符串中剥离封闭的 '[]'。
key_expr = Word(alphas, alphanums+'_')
value_expr = QuotedString('[',endQuoteChar=']')
根据这些基本元素,我们可以定义单个键值对的外观,即一个键、一个“:”和一个值。 Pyparsing 覆盖 '+' 运算符以指示我们正在从这些简单的键和值基元构建更大的表达式。 (定界的 ':' 字符将从解析的结果中被抑制,因为我们在上面指出任何内联文字都将使用 pyparsing Suppress class 添加到表达式中。)
Pyparsing 还默认 return 将所有已解析的字符串作为已解析元素的平面列表。为了维护键值结构,我们可以将我们的键值对封装在一个 pyparsing 组中:
key_value_pair = Group(key_expr + ':' + value_expr)
最后,您的表达式包含一个或多个这样的键值对,因此我们使用 pyparsing 的 OneOrMore class 来表示:
parser = OneOrMore(key_value_pair)
使用这个解析器,让我们运行根据您的输入字符串:
source = "home_id: [redacted] id: [7] name: [] model: []"
results = parser.parseString(source, parseAll=True)
Pyparsing returns 解析数据在一个ParseResults 对象中,它具有非常丰富的post-解析API。解析后的值可以像数据只是 returned 作为列表一样访问,或者如果在解析器定义期间指定了键,则可以通过键值访问。或者我们可以使用 ParseResults 的 asList() 方法将结果视为实际的 Python 列表:
print results.asList()
给出:
[['home_id', 'redacted'], ['id', '7'], ['name', ''], ['model', '']]
如果你甚至对 Python 有初步了解,你就会知道你可以将这种列表作为构造函数参数传递给字典 class,并得到一个键为 'home_id', 'id', 等对应的值.
print dict(results.asList())
给出:
{'home_id': 'redacted', 'model': '', 'id': '7', 'name': ''}
这应该足以让您开始使用 pyparsing。但是还有一个更高级的步骤,让 pyparsing 将这些键和值定义为解析过程的一部分。正如 Pyparsing 定义 Group 以向 returned 结果添加结构一样,pyparsing 还定义了 Dict class 以添加数据的解析时解释,将每个组的第一个元素作为键,并且每个组的剩余元素作为值,并使用在输入字符串中找到的值动态定义结果名称。我们简单地将我们之前定义的解析器包装在一个 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 class 也有一个 asDict() 方法来 return 你的数据作为标准 Python dict:
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()
另一种正则表达式解决方案。
>>> 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': ''}