views:

190

answers:

7

Hello, I have a list of library filenames that I need to filter against regular expression and then extract version number from those that match. This is the obvious way to do that:

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))

That produces the following list:

['3.3.1', '3.2.0']

Yet I feel that loop is not very 'Python style' and feel it should be possible to replace 'for' loop above with some smart one-liner. Suggestions?

+7  A: 

How about a list comprehension?

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']
Matt Anderson
+3  A: 

You could do this:

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

I don't think it's very readable, though...

Maybe it's clearer done in two steps:

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

you don't really need to bother with regex for your simple case

>>> 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
>>>

Do further checking to get those with "dots".

ghostdog74
A: 

There's nothing that isn't pythonic about using a standard for loop. However, you can use the map() function to generate a new list based on the results from a function run against each item in the list.

Soviut
A: 

How about this one:

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']
Andrey Vlasovskikh
A: 
sateesh
+2  A: 

One more one-liner just to show other ways (I've also cleaned regexp a bit):

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

But note, that your original version is more readable than all suggestions. Is it worth to change?

Denis Otkidach
Thanks for both 'findall' and 'sum'!Regarding readability - already used to it with all stl and boost algorithms :)
Aleksei Potov