我有一个库文件名列表,需要根据正则表达式进行过滤,然后从匹配的文件名中提取版本号。这是执行此操作的明显方法:

libs = ['libIce.so.33', 'libIce.so.3.3.1', 'libIce.so.32', 'libIce.so.3.2.0']
versions = []
regex = re.compile('libIce.so\.([0-9]+\.[0-9]+\.[0-9]+)')
for l in libs:
    m = regex.match(l)
    if m:
        versions.append(m.group(1))

这会产生以下列表:

['3.3.1', '3.2.0']

然而我觉得这个循环不是很“Python 风格”,并且觉得应该可以用一些智能单行代码替换上面的“for”循环。建议?

有帮助吗?

解决方案

如何列表理解?

In [5]: versions = [m.group(1) for m in [regex.match(lib) for lib in libs] if m] 
In [6]: versions
Out[6]: ['3.3.1', '3.2.0']

其他提示

还有一个一个班轮只是为了显示其他方式(我也清理正则表达式了一下):

regex = re.compile(r'^libIce\.so\.([0-9]+\.[0-9]+\.[0-9]+)$')
sum(map(regex.findall, libs), [])

但请注意,您的原始版本比所有的建议更具可读性。是否值得改变?

您可以这样做:

versions = [m.group(1) for m in [regex.match(l) for l in libs] if m]

我不认为这是非常具有可读性,虽然...

也许它更清晰分两步进行:

matches = [regex.match(l) for l in line]
versions = [m.group(1) for m in matches if m]

有什么,是不是Python的有关使用标准循环。但是,您可以使用地图()函数生成一个新的基于来自针对列表中的每个项目上运行的函数的结果列表中。

你并不真的需要用正则表达式来打扰你的简单情况。

>>> libs = ['libIce.so.33', 'libIce.so.3.3.1', 'libIce.so.32', 'libIce.so.3.2.0']
>>> libs
['libIce.so.33', 'libIce.so.3.3.1', 'libIce.so.32', 'libIce.so.3.2.0']
>>> for i in libs:
...   print i.split("so.")
...
['libIce.', '33']
['libIce.', '3.3.1']
['libIce.', '32']
['libIce.', '3.2.0']
>>> for i in libs:
...   print i.split("so.")[-1]
...
33
3.3.1
32
3.2.0
>>>

做进一步的检查,以获得那些具有“点”。

这个怎么样:

import re

def matches(regexp, list):
    'Regexp, [str] -> Iterable(Match or None)'
    return (regexp.match(s) for s in list)

libs = ['libIce.so.33', 'libIce.so.3.3.1', 'libIce.so.32', 'libIce.so.3.2.0']
regexp = re.compile('libIce.so\.([0-9]+\.[0-9]+\.[0-9]+)')
versions = [m.group(1) for m in matches(regexp, libs) if m is not None]

>>> print versions
['3.3.1', '3.2.0']

我能想到的一个办法是结合“地图”和列表理解。结果 将溶液看起来如下:

import re  
libs = ['libIce.so.33', 'libIce.so.3.3.1', 'libIce.so.32', 'libIce.so.3.2.0']  
versions = []  

regex = re.compile('libIce.so\.([0-9]+\.[0-9]+\.[0-9]+)')  

def match(s):  
    m = regex.match(s)  
    if m:  
        return m.group(1)  

versions = [x for x in map(match,libs) if x]  

开始 Python 3.8, ,以及引入 赋值表达式 (PEP 572) (:= 运算符),可以在列表理解中使用局部变量,以避免调用正则表达式匹配结果的两倍:

# libs = ['libIce.so.33', 'libIce.so.3.3.1', 'libIce.so.32', 'libIce.so.3.2.0']
# pattern = re.compile(r'libIce.so\.([0-9]+\.[0-9]+\.[0-9]+)')
[match.group(1) for lib in libs if (match := pattern.match(lib))]
# ['3.3.1', '3.2.0']

这:

  • 评价的名称 pattern.match(lib) 作为变量 match (这是 None 或一个 re.Match 目的)
  • 用这个 match 就地命名表达式(或者 None 或一个 Match) 过滤掉不匹配的元素
  • 并重复利用 match 通过提取第一组(match.group(1)).
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top