In Python durch Komma und Leerzeichen trennen

346

Ich habe Python-Code, der durch Komma geteilt wird, aber das Leerzeichen nicht entfernt:

>>> string = "blah, lots  ,  of ,  spaces, here "
>>> mylist = string.split(',')
>>> print mylist
['blah', ' lots  ', '  of ', '  spaces', ' here ']

Ich würde lieber Leerzeichen wie folgt entfernen:

['blah', 'lots', 'of', 'spaces', 'here']

Ich bin mir bewusst, dass ich die Liste durchlaufen und jedes Element entfernen () kann, aber da dies Python ist, gibt es vermutlich eine schnellere, einfachere und elegantere Möglichkeit, dies zu tun.

Mr_Chimp
quelle

Antworten:

594

Verwenden Sie das Listenverständnis - einfacher und genauso einfach zu lesen wie eine forSchleife.

my_string = "blah, lots  ,  of ,  spaces, here "
result = [x.strip() for x in my_string.split(',')]
# result is ["blah", "lots", "of", "spaces", "here"]

Siehe: Python-Dokumente zum Listenverständnis
Eine gute 2-Sekunden-Erklärung zum Listenverständnis.

Sean Vieira
quelle
1
Super gut! Ich habe ein Element wie folgt hinzugefügt, um die leeren Listeneinträge zu entfernen. > text = [x.strip () für x in text.split ('.') wenn x! = '']
RandallShanePhD
@ Sean: War ungültiger / unvollständiger Python-Code Ihre "ursprüngliche Absicht des Beitrags"? Laut den Review-Wichsern war es: stackoverflow.com/review/suggested-edits/21504253 . Können Sie ihnen bitte etwas anderes sagen, indem Sie die Korrektur vornehmen, wenn sie (erneut) falsch sind?
Futter
Das Original wurde von einem REPL Kopie kleistert (wenn ich mich richtig erinnere) , und das Ziel war das Verständnis des zugrunde liegenden Konzepts (mit Liste Verständnis , eine Operation auszuführen) - aber du hast recht, es macht mehr Sinn , wenn Sie sehen , dass die Liste Verständnis erzeugt eine neue Liste.
Sean Vieira
24

Mit einem regulären Ausdruck teilen. Hinweis: Ich habe den Fall mit führenden Leerzeichen allgemeiner gestaltet. Das Listenverständnis besteht darin, die Nullzeichenfolgen vorne und hinten zu entfernen.

>>> import re
>>> string = "  blah, lots  ,  of ,  spaces, here "
>>> pattern = re.compile("^\s+|\s*,\s*|\s+$")
>>> print([x for x in pattern.split(string) if x])
['blah', 'lots', 'of', 'spaces', 'here']

Dies funktioniert auch dann, wenn ^\s+es nicht übereinstimmt:

>>> string = "foo,   bar  "
>>> print([x for x in pattern.split(string) if x])
['foo', 'bar']
>>>

Hier ist, warum Sie ^ \ s + benötigen:

>>> pattern = re.compile("\s*,\s*|\s+$")
>>> print([x for x in pattern.split(string) if x])
['  blah', 'lots', 'of', 'spaces', 'here']

Sehen Sie die führenden Räume in bla?

Erläuterung: Oben wird der Python 3-Interpreter verwendet, die Ergebnisse in Python 2 sind jedoch dieselben.

tbc0
quelle
8
Ich glaube, es [x.strip() for x in my_string.split(',')]ist pythonischer für die gestellte Frage. Vielleicht gibt es Fälle, in denen meine Lösung notwendig ist. Ich werde diesen Inhalt aktualisieren, wenn ich auf einen stoße.
TBC0
Warum ist ^\s+notwendig? Ich habe Ihren Code ohne ihn getestet und er funktioniert nicht, aber ich weiß nicht warum.
Laike9m
Wenn ich benutze re.compile("^\s*,\s*$"), ist das Ergebnis [' blah, lots , of , spaces, here '].
Laike9m
@ laike9m, ich habe meine Antwort aktualisiert, um Ihnen den Unterschied zu zeigen. ^\s+macht. Wie Sie selbst sehen können, werden ^\s*,\s*$auch die gewünschten Ergebnisse nicht zurückgegeben. Wenn Sie also mit einem regulären Ausdruck teilen möchten, verwenden Sie ^\s+|\s*,\s*|\s+$.
TBC0
Die erste Übereinstimmung ist leer, wenn das führende Muster (^ \ s +) nicht übereinstimmt, sodass Sie für die Zeichenfolge "foo, bar" so etwas wie ['', 'foo', 'bar'] erhalten.
Steeve McCauley
21

Ich kam, um hinzuzufügen:

map(str.strip, string.split(','))

aber sah, dass es bereits von Jason Orendorff in einem Kommentar erwähnt worden war .

Als ich Glenn Maynards Kommentar in derselben Antwort las, in der Listenverständnisse über die Karte vorgeschlagen wurden, begann ich mich zu fragen, warum. Ich nahm an, dass er aus Performancegründen meinte, aber natürlich könnte er aus stilistischen Gründen gemeint sein oder etwas anderes (Glenn?).

Ein schneller (möglicherweise fehlerhafter?) Test auf meiner Box, bei dem die drei Methoden in einer Schleife angewendet wurden, ergab:

[word.strip() for word in string.split(',')]
$ time ./list_comprehension.py 
real    0m22.876s

map(lambda s: s.strip(), string.split(','))
$ time ./map_with_lambda.py 
real    0m25.736s

map(str.strip, string.split(','))
$ time ./map_with_str.strip.py 
real    0m19.428s

machen map(str.strip, string.split(','))den Sieger, obwohl es scheint , sie sind alle in derselben Liga.

Natürlich sollte eine Karte (mit oder ohne Lambda) aus Leistungsgründen nicht unbedingt ausgeschlossen werden, und für mich ist sie mindestens so klar wie ein Listenverständnis.

Bearbeiten:

Python 2.6.5 unter Ubuntu 10.04

Sean
quelle
15

Entfernen Sie einfach den Leerraum aus der Zeichenfolge, bevor Sie ihn teilen.

mylist = my_string.replace(' ','').split(',')
user489041
quelle
10
Ein Problem, wenn die durch Kommas getrennten Elemente eingebettete Leerzeichen enthalten, z "you just, broke this".
Robert Rossney
1
Geeze, ein -1 dafür. Ihr seid hart. Es löste sein Problem, vorausgesetzt, seine Beispieldaten bestanden nur aus einzelnen Wörtern und es gab keine Spezifikation, dass die Daten Phrasen sein würden. Aber w / e, ich denke, so rollt ihr hier herum.
user489041
Na trotzdem danke, User. Um fair zu sein, habe ich speziell nach split gefragt und dann strip () und strip entfernt führende und nachfolgende Leerzeichen und berührt nichts dazwischen. Eine kleine Änderung und Ihre Antwort würden jedoch perfekt funktionieren: mylist = mystring.strip (). Split (','), obwohl ich nicht weiß, ob dies besonders effizient ist.
Mr_Chimp
12

Ich weiß, dass dies bereits beantwortet wurde, aber wenn Sie dies häufig beenden, sind reguläre Ausdrücke möglicherweise der bessere Weg:

>>> import re
>>> re.sub(r'\s', '', string).split(',')
['blah', 'lots', 'of', 'spaces', 'here']

Das \sentspricht jedem Leerzeichen, und wir ersetzen es einfach durch eine leere Zeichenfolge ''. Weitere Informationen finden Sie hier: http://docs.python.org/library/re.html#re.sub

Brad Montgomery
quelle
3
Ihr Beispiel funktioniert nicht mit Zeichenfolgen, die Leerzeichen enthalten. "zum Beispiel dies, eins" würde "für", "beispielhaft", "eins" werden. Ohne zu sagen, dass es eine schlechte Lösung ist (es funktioniert perfekt in meinem Beispiel), hängt es nur von der jeweiligen Aufgabe ab!
Mr_Chimp
Ja, das ist sehr richtig! Sie könnten wahrscheinlich den regulären Ausdruck so anpassen, dass er Zeichenfolgen mit Leerzeichen verarbeiten kann, aber wenn das Listenverständnis funktioniert, würde ich sagen, bleiben Sie dabei;)
Brad Montgomery
2
import re
result=[x for x in re.split(',| ',your_string) if x!='']

Das funktioniert gut für mich.

Zieng
quelle
2

re (wie in regulären Ausdrücken) ermöglicht das Aufteilen auf mehrere Zeichen gleichzeitig:

$ string = "blah, lots  ,  of ,  spaces, here "
$ re.split(', ',string)
['blah', 'lots  ', ' of ', ' spaces', 'here ']

Dies funktioniert nicht gut für Ihre Beispielzeichenfolge, aber gut für eine durch Kommas getrennte Liste. Für Ihre Beispielzeichenfolge können Sie die re.split-Leistung kombinieren, um Regex-Muster zu teilen , um einen "Split-on-this-or-that" -Effekt zu erzielen.

$ re.split('[, ]',string)
['blah',
 '',
 'lots',
 '',
 '',
 '',
 '',
 'of',
 '',
 '',
 '',
 'spaces',
 '',
 'here',
 '']

Leider ist das hässlich, aber ein filterWille macht den Trick:

$ filter(None, re.split('[, ]',string))
['blah', 'lots', 'of', 'spaces', 'here']

Voila!

Dannid
quelle
2
Warum nicht einfach re.split(' *, *', string)?
Paul Tomblin
4
@ PaulTomblin gute Idee. Man kann dies auch getan haben: re.split('[, ]*',string)für den gleichen Effekt.
Dannid
Dannid wurde mir nach dem Schreiben klar, dass es am Anfang und am Ende keine Leerzeichen entfernt, wie es die Antwort von @ tbc0 tut.
Paul Tomblin
@PaulTomblinheh, und meine Gegenargumentation [, ]*hinterlässt am Ende der Liste eine leere Zeichenfolge. Ich denke, Filter ist immer noch eine nette Sache, um sie dort hineinzuwerfen oder sich an das Listenverständnis zu halten, wie es die Top-Antwort tut.
Dannid
1

map(lambda s: s.strip(), mylist)wäre ein bisschen besser als explizite Schleifen. Oder für das Ganze auf einmal:map(lambda s:s.strip(), string.split(','))

user470379
quelle
10
Tipp: Überprüfen mapSie jedes Mal , wenn Sie es verwenden , insbesondere wenn Sie lambdaes verwenden, noch einmal, ob Sie ein Listenverständnis verwenden sollten.
Glenn Maynard
11
Sie können das Lambda mit vermeiden map(str.strip, s.split(',')).
Jason Orendorff
1
s = 'bla, buu, jii'

sp = []
sp = s.split(',')
for st in sp:
    print st
Parikshit Pandya
quelle
1
import re
mylist = [x for x in re.compile('\s*[,|\s+]\s*').split(string)]

Einfach Komma oder mindestens ein Leerzeichen mit / ohne vorhergehende / nachfolgende Leerzeichen.

Bitte versuche!

GyuHyeon Choi
quelle
0

map(lambda s: s.strip(), mylist)wäre ein bisschen besser als explizite Schleifen.
Oder für das Ganze auf einmal:

map(lambda s:s.strip(), string.split(','))

Das ist im Grunde alles was Sie brauchen.

DJbigpenis
quelle