使用re.findall捕获正则表达式中的命名组
当我试图回答这个问题时:在Python中用正则表达式分割年龄和数值,我发现我需要重新排列从findall得到的结果中的组。例如:
data = """34% passed 23% failed 46% deferred"""
result = {key:value for value, key in re.findall('(\w+)%\s(\w+)', data)}
print(result)
>>> {'failed': '23', 'passed': '34', 'deferred': '46'}
这里findall的结果是:
>>> re.findall('(\w+)%\s(\w+)', data)
>>> [('34', 'passed'), ('23', 'failed'), ('46', 'deferred')]
有没有办法改变或指定这些组的顺序,让re.findall返回:
[('passed', '34'), ('failed', '23'), ('deferred', '46')]
为了更清楚,我想说明一下,这个问题是:
是否可以指定顺序或重新排列re.findall函数返回的组?
我用上面的例子创建了一个字典,以提供一个理由或使用场景,说明你为什么想改变顺序(把键当成值,把值当成键)。
进一步说明:
为了处理更大更复杂的正则表达式中的组,你可以给组命名,但这些名字只有在使用re.search或re.match时才能访问。根据我所了解,findall返回的元组中的组有固定的索引,问题是有没有人知道这些索引怎么修改。这将有助于更轻松和直观地处理组。
3 个回答
根据提问者对我第一个回答的评论:如果你只是想重新排列一个包含二元组的列表,比如这样:
[('34', 'passed'), ('23', 'failed'), ('46', 'deferred')]
... 想要变成这样,每个元素的顺序都反过来:
[('passed', '34'), ('failed', '23'), ('deferred', '46')]
其实有个简单的办法:使用列表推导式和切片语法 sequence[::-1]
来反转每个元组里的元素顺序:
a = [('34', 'passed'), ('23', 'failed'), ('46', 'deferred')]
b = [x[::-1] for x in a]
print b
正如你在第二个例子中提到的,re.findall
会按照原来的顺序返回分组。
问题在于,标准的 Python dict
类型并不会保留键的顺序。在 Python 2.x 的手册中有明确说明,但在 Python 3.x 中也是如此:https://docs.python.org/2/library/stdtypes.html#dict.items
你应该使用的是 collections.OrderedDict
:
from collections import OrderedDict as odict
data = """34% passed 23% failed 46% deferred"""
result = odict((key,value) for value, key in re.findall('(\w+)%\s(\w+)', data))
print(result)
>>> OrderedDict([('passed', '34'), ('failed', '23'), ('deferred', '46')])
注意,你必须使用成对构造器的形式(dict((k,v) for k,v in ...
),而不是使用 dict
的推导式({k:v for k,v in ...}
)。这是因为后者会创建 dict
类型的实例,而这种类型的实例在转换为 OrderedDict
时会丢失键的顺序……而这正是你最初想要保留的。