我有一个库文件名列表,我需要对正则表达式进行过滤,然后从匹配的文件中提取版本号。这是明显的方法:
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'循环。 建议?
答案 0 :(得分:19)
列表理解怎么样?
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']
答案 1 :(得分:8)
还有一个单行显示其他方式(我还清理了一点regexp):
regex = re.compile(r'^libIce\.so\.([0-9]+\.[0-9]+\.[0-9]+)$')
sum(map(regex.findall, libs), [])
但请注意,您的原始版本比所有建议更具可读性。是否值得改变?
答案 2 :(得分:5)
你可以这样做:
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]
答案 3 :(得分:1)
使用标准for循环没有什么不是pythonic。但是,您可以使用map()函数根据针对列表中每个项目运行的函数的结果生成新列表。
答案 4 :(得分:0)
你真的不需要为你的简单案例打扰正则表达式
>>> 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
>>>
进一步检查以获得带有“点”的那些。
答案 5 :(得分: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']
答案 6 :(得分: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]
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]
答案 7 :(得分:0)
从Python 3.8
开始并引入assignment expressions (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)
。