68

受到一个现已删除的问题的启发;给定带有命名组的正则表达式,是否有一种方法findall可以返回dict带有命名捕获组的列表而不是列表tuple

鉴于:

>>> import re
>>> text = "bob sue jon richard harry"
>>> pat = re.compile('(?P<name>[a-z]+)\s+(?P<name2>[a-z]+)')
>>> pat.findall(text)
[('bob', 'sue'), ('jon', 'richard')]

应该改为:

[{'name': 'bob', 'name2': 'sue'}, {'name': 'jon', 'name2': 'richard'}]
4

4 回答 4

135
>>> import re
>>> s = "bob sue jon richard harry"
>>> r = re.compile('(?P<name>[a-z]+)\s+(?P<name2>[a-z]+)')
>>> [m.groupdict() for m in r.finditer(s)]
[{'name2': 'sue', 'name': 'bob'}, {'name2': 'richard', 'name': 'jon'}]
于 2012-06-19T15:17:49.570 回答
14

你可以切换到查找器

>>> import re
>>> text = "bob sue jon richard harry"
>>> pat = re.compile('(?P<name>[a-z]+)\s+(?P<name2>[a-z]+)')
>>> for m in pat.finditer(text):
...     print m.groupdict()
... 
{'name2': 'sue', 'name': 'bob'}
{'name2': 'richard', 'name': 'jon'}
于 2012-06-19T15:19:53.433 回答
7

如果您使用匹配:

r = re.match('(?P<name>[a-z]+)\s+(?P<name2>[a-z]+)', text)
r.groupdict()

文档在这里

于 2017-04-21T17:22:40.100 回答
1

没有内置的方法可以做到这一点,但可以通过使用列表推导来实现预期的结果。

[dict([[k, i if isinstance(i, str) else i[v-1]] for k,v in pat.groupindex.items()]) for i in pat.findall(text)]

使用友好的格式:

>>> [
...     dict([
...         [k, i if isinstance(i, str) else i[v-1]]
...         for k,v in pat.groupindex.items()
...     ])
...     for i in pat.findall(text)
... ]

我们使用列表推导式构造一个列表,遍历结果,findall其中要么是字符串列表,要么是元组列表(0 或 1 个捕获组导致 的列表str)。

对于结果中的每个项目,我们dict从另一个列表推导中构造一个,该推导是从groupindex编译模式的字段生成的,如下所示:

>>> pat.groupindex
{'name2': 2, 'name': 1}

为 中的每个项目构造一个列表groupindex,如果来自的项目findall是一个元组,则使用来自的组号groupindex来查找正确的项目,否则将该项目分配给(仅现存的)命名组。

[k, i if isinstance(i, str) else i[v-1]]

最后,从字符串列表的列表构造一个 dict。

请注意,groupindex它仅包含命名组,因此结果中将省略未命名的捕获组dict

结果:

[dict([[k, i if isinstance(i, str) else i[v-1]] for k,v in pat.groupindex.items()])  for i in pat.findall(text)]
[{'name2': 'sue', 'name': 'bob'}, {'name2': 'richard', 'name': 'jon'}]
于 2012-06-19T15:05:39.307 回答