2009-11-03 8 views
9

Ich habe eine Liste von Bibliotheksdateinamen, die ich gegen regulären Ausdruck filtern muss und dann extrahiere Versionsnummer von denen, die übereinstimmen. Dies ist die offensichtliche Art und Weise, das zu tun:Python-Liste Filterung und Transformation

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

dass die folgende Liste erzeugt:

['3.3.1', '3.2.0'] 

Dennoch glaube ich, dass Schleife nicht sehr ‚Python-Stil‘ ist und das Gefühl, es möglich sein soll, ersetzen " für 'Schleife oben mit etwas intelligentem Einzeiler. Vorschläge?

Antwort

19

Wie wäre es mit einem Listenverständnis?

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'] 
5

Sie können dies tun:

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

Ich glaube nicht, es sehr gut lesbar ist, aber ...

Vielleicht ist es klarer in zwei Schritten getan:

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

Sie brauchen nicht wirklich mit Regex für Ihren einfachen Fall zu beschäftigen

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

Führen Sie weitere Prüfungen durch, um solche mit "Punkten" zu erhalten.

1

Es gibt nichts, das nicht pythonisch ist mit einem Standard für Schleife. Sie können jedoch die Funktion map() verwenden, um eine neue Liste basierend auf den Ergebnissen einer Funktion zu erstellen, die für jedes Element in der Liste ausgeführt wird.

0

Wie wäre es diese:

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'] 
0

Ein Weg, ich denke, könnte die ‚Karte‘ und Liste Verständnis zu kombinieren war.
Die Lösung sieht wie folgt:

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] 

8

Ein weiterer Einzeiler nur andere Wege, um zu zeigen, (I auch regexp ein bisschen gereinigt haben):

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

Aber beachten Sie, dass Ihre Originalversion ist lesbarer als alle Vorschläge. Lohnt es sich zu ändern?

+1

Danke für 'findall' und 'sum'! In Bezug auf Lesbarkeit - bereits mit allen STL-und Boost-Algorithmen verwendet :) –

+0

aus irgendeinem Grund macht mir das viel mehr Sinn als die angenommene/upvoted Antwort. –