2009-05-15 4 views
20

Stellen Sie sich eine Zeichenfolge vor, wie 'Agh # $% #% 2341- -! Zdrkfd' und ich möchte nur einige Operationen ausführen, so dass nur die Kleinbuchstaben zurückgegeben werden (als Beispiel), die in diesem Fall bringen würde "ghzdrkfd".Wie filtern Sie eine Zeichenfolge so, dass nur Zeichen in Ihrer Liste zurückgegeben werden?

Wie machst du das in Python? Der offensichtliche Weg wäre, eine Liste von Zeichen, 'a' bis 'z', zu erstellen, dann über die Zeichen in meiner Zeichenkette zu iterieren und eine neue Zeichenkette von Zeichen in meiner Liste zu erstellen. Das scheint primitiv zu sein.

Ich habe mich gefragt, ob reguläre Ausdrücke angemessen sind. Das Ersetzen unerwünschter Zeichen scheint problematisch zu sein, und ich bevorzuge eher das Whitelisting als das Blacklisting. Die .match Funktion scheint nicht angemessen. Ich habe die entsprechende Seite auf der Python-Seite angeschaut, aber keine Methode gefunden, die zu passen scheint.

Wenn reguläre Ausdrücke nicht geeignet sind und der richtige Ansatz Looping ist, gibt es eine einfache Funktion, die einen String in eine Liste "explodiert"? Oder treffe ich gerade einen anderen für die Schleife?

+0

http://stackoverflow.com/questions/89909/in-python-how-to-i-verify-that-a-string-only-contains-letters-numbers-underscor/ – Javier

Antwort

4
s = 'ASDjifjASFJ7364' 
s_lowercase = ''.join(filter(lambda c: c.islower(), s)) 
print s_lowercase #print 'jifj' 
+3

Sie müssen nicht anrufen Liste auf s. String-Objekte sind iterierbar. –

17
s = 'Agh#$%#%2341- -!zdrkfd' 
print ''.join(c for c in s if c.islower()) 

String-Objekte sind iterable; Es besteht keine Notwendigkeit, die Zeichenfolge in eine Liste zu "explodieren". Sie können die gewünschte Bedingung in das Listenverständnis einfügen und die Zeichen entsprechend filtern.

Sie könnten dies auch mit einem Regex implementieren, aber dies wird nur die Schleife ausblenden. Die Bibliothek für reguläre Ausdrücke muss weiterhin die Zeichen der Zeichenfolge durchlaufen, um sie zu filtern.

+0

isalpha() wird nicht benötigt, da Nicht-Alpha-Zeichen false auf islower() zurückgeben –

+0

@coonj Guter Punkt. Fest. –

+3

Dies kann auch geändert werden, um mit einer benutzerdefinierten Zeichenliste zu arbeiten, indem 'c.islower()' z. 'c in" abcDEF "'. –

0

Ich würde eine Regex verwenden. Für Kleinbuchstaben [a-z].

4
>>> s = 'Agh#$%#%2341- -!zdrkfd' 
>>> ''.join(i for i in s if i in 'qwertyuiopasdfghjklzxcvbnm') 
'ghzdrkfd' 
5

Verwenden eines regulären Ausdrucks ist leicht genug, vor allem für dieses Szenario:

>>> import re 
>>> s = 'ASDjifjASFJ7364' 
>>> re.sub(r'[^a-z]+', '', s) 
'jifj' 

Wenn Sie tun dies oft zu planen, ist es am besten, den regulären Ausdruck, bevor die Hand zu kompilieren:

>>> import re 
>>> s = 'ASDjifjASFJ7364' 
>>> r = re.compile(r'[^a-z]+') 
>>> r.sub('', s) 
'jifj' 
+0

Um fair zu sein Ich habe den Test erneut auf Ihrer vorkompilierten Version ausgeführt und es ist immer noch langsamer als übersetzen. –

+0

Der Regex sollte '[^ a-z] +' sein - dies verbessert die Leistung erheblich. – gnud

+0

@gnud, Sie haben Recht, die Leistung zu verbessern. Aber es ist immer noch viel langsamer als das Übersetzen. –

0
import string 
print "".join([c for c in "Agh#$%#%2341- -!zdrkfd" if c in string.lowercase]) 
30

Wenn Sie nach Effizienz suchen. Die Verwendung der translate Funktion ist die schnellste, die Sie erhalten können.

Es kann verwendet werden, um Zeichen schnell zu ersetzen und/oder zu löschen.

import string 
delete_table = string.maketrans(
    string.ascii_lowercase, ' ' * len(string.ascii_lowercase) 
) 
table = string.maketrans('', '') 

"Agh#$%#%2341- -!zdrkfd".translate(table, delete_table) 

In Python 2.6: Das ist Methode ist viel schneller als jede andere Sie die zweite Tabelle nicht mehr

import string 
delete_table = string.maketrans(
    string.ascii_lowercase, ' ' * len(string.ascii_lowercase) 
) 
"Agh#$%#%2341- -!zdrkfd".translate(None, delete_table) 

benötigen. Natürlich müssen Sie die delete_table irgendwo speichern und verwenden. Aber selbst wenn Sie es nicht speichern und jedes Mal neu erstellen, wird es immer noch schneller als andere vorgeschlagene Methoden sein.

Um meine Ansprüche hier sind die Ergebnisse zu bestätigen:

for i in xrange(10000): 
    ''.join(c for c in s if c.islower()) 

real 0m0.189s 
user 0m0.176s 
sys 0m0.012s 

Während des Laufens den regulären Ausdruck Lösung:

for i in xrange(10000): 
    re.sub(r'[^a-z]', '', s) 

real 0m0.172s 
user 0m0.164s 
sys 0m0.004s 

[Auf Anfrage] Wenn Sie vorab kompilieren den regulären Ausdruck:

r = re.compile(r'[^a-z]') 
for i in xrange(10000): 
    r.sub('', s) 

real 0m0.166s 
user 0m0.144s 
sys 0m0.008s 

Ausführen der Übersetzungsmethode t er gleich oft nahm:

real 0m0.075s 
user 0m0.064s 
sys 0m0.012s 
+2

Um fair zu sein, sollten Sie die Regex außerhalb der Schleife kompilieren. – Unknown

+0

Ich vergleiche die besten vorgeschlagenen Lösungen. So schrieb Paolo Bergantino seinen Ausdruck. –

+0

Ich schrieb es als eine einmalige Lösung, es wäre offensichtlich am besten kompiliert, also sollten Sie es als solches vergleichen. –

1

Hier eine Lösung ist, wenn Sie bei der Arbeit an Saiten speziell interessiert sind:

s = 'Agh#$%#%2341- -!zdrkfd' 
lowercase_chars = [chr(i) for i in xrange(ord('a'), ord('z') + 1)] 
whitelist = set(lowercase_chars) 
filtered_list = [c for c in s if c in whitelist] 

Die Weiße Liste ist eigentlich ein Satz (keine Liste) für Effizienz.

Wenn Sie einen String benötigen, verwenden join():

filtered_str = ''.join(filtered_list) 

filter() ist eine generische Lösung. Aus der Dokumentation (http://docs.python.org/library/functions.html):

Filter (Funktion, iterable)

Erstellen Sie eine Liste von diesen Elementen von iterable für die Funktion true zurückgibt. iterierbar kann entweder eine Sequenz, ein Container, der Iteration unterstützt, oder ein Iterator sein. Wenn iterable eine Zeichenfolge oder ein Tupel ist, hat das Ergebnis auch diesen Typ; Ansonsten ist es immer eine Liste. Wenn die Funktion None ist, wird die Identity-Funktion angenommen, dh alle Elemente von Iterable, die false sind, werden entfernt.

Dies wäre eine Möglichkeit, mit filter() sein:

filtered_list = filter(lambda c: c.islower(), s) 
0
import string 

print filter(string.lowercase.__contains__, "lowerUPPER") 
print filter("123".__contains__, "a1b2c3") 
1

Eine allgemeine und verständliche Lösung, die eine inputstring und filtern sie gegen eine whitelist von Zeichen zu nehmen:

inputstring = "Agh#$%#%2341- -!zdrkfd" 
whitelist = "abcdefghijklmnopqrstuvwxyz" 
remove = inputstring.translate(None, whitelist) 
result = inputstring.translate(None, remove) 
print result 

Diese Drucke

Die erste string.translate entfernt alle Zeichen in der Whitelist von der Inputstring. Dies gibt uns die Zeichen, die wir entfernen möchten. Der zweite string.translate Aufruf entfernt diese aus der Inputstring und erzeugt das gewünschte Ergebnis.