Warum werden leere Zeichenfolgen in split () - Ergebnissen zurückgegeben?

120

Was ist der Sinn der '/segment/segment/'.split('/')Rückkehr ['', 'segment', 'segment', '']?

Beachten Sie die leeren Elemente. Wenn Sie ein Trennzeichen aufteilen, das sich zufällig an Position eins und ganz am Ende einer Zeichenfolge befindet, welchen zusätzlichen Wert erhalten Sie, wenn die leere Zeichenfolge von jedem Ende zurückgegeben wird?

Orokusaki
quelle
1
Ich habe die gleiche Frage und habe sie lange gesucht. Jetzt verstehe ich, dass die leeren Ergebnisse wirklich wichtig sind. Danke für deine Frage.
Smaragdhieu
2
Eine Lösung besteht darin strip(), führende und nachfolgende geteilte Zeichen vor dem Teilen von der Zeichenfolge zu '/segment/segment/'.strip('/').split('/')
entfernen

Antworten:

178

str.splitergänzt str.join, so

"/".join(['', 'segment', 'segment', ''])

holt dir die ursprüngliche Saite zurück.

Wenn die leeren Zeichenfolgen nicht vorhanden '/'wären, würden die ersten und letzten nach dem fehlenjoin()

John La Rooy
quelle
11
Einfach, aber beantwortet die Frage vollständig.
Orokusaki
Ich war schockiert zu entdecken, dass geschweifte Anführungszeichen tatsächlich in Python gültig sind ... aber, aber ... wie? Die Dokumente scheinen dies nicht zu erwähnen.
Tim Pietzcker
@ Tim, ich habe keine Ahnung, wie diese Zitate dort reingekommen sind : /
John La Rooy
7
Sie verwenden also nicht Microsoft Word als Python-IDE? :)
Tim Pietzcker
1
@ aaa90210 Wer hat gesagt, dass einfache Antworten nicht die besten sind? Es war ein Kommentar (erstens vor 5 Jahren) darüber, wie einfach die Antwort war, aber die Frage vollständig beantwortete. Die Verwendung von "aber" in einem Satz bedeutet nichts Schlechtes. Eine nicht einfache Antwort könnte eine vollständigere Antwort gewesen sein (z. B. einschließlich relevanter Entscheidungen oder eines PEP in Bezug auf die angegebene Funktionalität).
Orokusaki
88

Um leere Zeichenfolgen zu entfernen, die in den split()Ergebnissen zurückgegeben werden, sollten Sie sich die filterFunktion ansehen .

Beispiel:

filter(None, '/segment/segment/'.split('/'))

kehrt zurück

['segment', 'segment']
Franck Dernoncourt
quelle
3
Vielen Dank dafür, ich weiß nicht, warum diese Antwort so weit unten ist, alles andere ist rudimentäres Zeug.
Wedge
6
Wenn Sie das Ergebnis in einer Liste sammeln möchten, anstatt ein Filterobjekt als Ausgabe zu erhalten, fügen Sie die gesamte Filterstruktur ein list(...).
Tim Visée
29

Hier sind zwei Hauptpunkte zu beachten:

  • Es ist vernünftig zu erwarten, dass das Ergebnis '/segment/segment/'.split('/')gleich ['segment', 'segment']ist, aber dann gehen Informationen verloren. Wenn es so split()funktioniert hat, wie Sie es wollten, wenn ich Ihnen das sage, a.split('/') == ['segment', 'segment']können Sie mir nicht sagen, was es awar.
  • Was soll das Ergebnis 'a//b'.split()sein? ['a', 'b']? oder ['a', '', 'b']? Dh, sollten split()benachbarte Begrenzer zusammengeführt werden? Wenn dies der Fall sein sollte, ist es sehr schwierig, Daten zu analysieren, die durch ein Zeichen begrenzt sind, und einige der Felder können leer sein. Ich bin ziemlich sicher , dass es viele Leute gibt , die nicht die leeren Werte im Ergebnis für den obigen Fall wollen!

Am Ende läuft es auf zwei Dinge hinaus:

Konsistenz: Wenn ich nTrennzeichen habe, aerhalte ich n+1Werte nach dem split().

Es sollte möglich sein, komplexe und einfache Dinge zu tun: Wenn Sie leere Zeichenfolgen als Ergebnis von ignorieren möchten split(), können Sie immer Folgendes tun:

def mysplit(s, delim=None):
    return [x for x in s.split(delim) if x]

aber wenn man die leeren Werte nicht ignorieren will, sollte man dazu in der Lage sein.

Die Sprache muss eine Definition auswählen: Es split()gibt zu viele verschiedene Anwendungsfälle, um standardmäßig alle Anforderungen zu erfüllen. Ich denke, dass Pythons Wahl eine gute und die logischste ist. (Abgesehen davon ist einer der Gründe, warum ich Cs nicht mag strtok(), dass es benachbarte Trennzeichen zusammenführt, was es extrem schwierig macht, ernsthaftes Parsen / Tokenisieren damit durchzuführen.)

Es gibt eine Ausnahme: a.split()Ohne Argument werden aufeinanderfolgende Leerzeichen zusammengedrückt, aber man kann argumentieren, dass dies in diesem Fall das Richtige ist. Wenn Sie das Verhalten nicht wollen, können Sie immer a.split(' ').

Alok Singhal
quelle
Für diejenigen, die sich fragen, ob es schneller ist, doppelte Leerzeichen zu nuklearisieren, dann zu teilen oder zu teilen und nur nicht leere Zeichenfolgen zu verwenden, bekomme ich python3 -m timeit "import re ; re.sub(' +', ' foo bar baz ', '').split(' ')"Folgendes : -> 875 ns pro Schleife; python3 -m timeit "[token for token in ' foo bar baz '.split(' ') if token]"-> 616 ns pro Schleife
s3cur3
8

Mit x.split(y)immer eine Liste von 1 + x.count(y)Artikel ist ein kostbares Regelmäßigkeit - wie @ gnibbler schon hat darauf hingewiesen , macht es splitund joingenau invers zueinander ist (wie sie sollte offensichtlich sein), ist es auch Karten genau die Semantik aller Arten von Trennzeichen verbundenen Aufzeichnungen ( B. csvDateizeilen [[ohne Anführungszeichen]], Zeilen aus /etc/groupUnix usw., ermöglicht es (wie in der Antwort von @ Roman erwähnt) eine einfache Überprüfung auf (z. B.) absolute oder relative Pfade (in Dateipfaden und URLs). und so weiter.

Eine andere Sichtweise ist, dass Sie Informationen nicht ohne Gewinn aus dem Fenster werfen sollten. Was würde man erreichen, wenn man x.split(y)gleichwertig wäre x.strip(y).split(y)? Nichts, natürlich - es ist einfach , die zweite Form zu verwenden , wenn das ist , was du meinst, aber wenn die erste Form willkürlich die zweiten verstanden wurde als würden Sie viel Arbeit zu tun , wenn Sie sich den ersten wollen ( was alles andere als selten ist, wie der vorige Absatz hervorhebt).

Das Denken in mathematischer Regelmäßigkeit ist jedoch die einfachste und allgemeinste Methode, mit der Sie sich das Entwerfen passabler APIs beibringen können. Um ein anderes Beispiel zu nehmen, ist es sehr wichtig , dass für jeden gültig xund y x == x[:y] + x[y:]- die sofort anzeigt , warum eine Extrem ein Aufschneiden soll ausgeschlossen werden. Je einfacher die invariante Behauptung ist, die Sie formulieren können, desto wahrscheinlicher ist es, dass die resultierende Semantik das ist, was Sie im wirklichen Leben benötigen - ein Teil der mystischen Tatsache, dass Mathematik im Umgang mit dem Universum sehr nützlich ist.

Versuchen Sie, die invariant für eine Formulierung splitDialekt , in dem vorderen und hinteren Begrenzungszeichen sind spezielle Gefasste ... Gegenbeispiel: String - Methoden wie isspacenicht maximal einfach sind - x.isspace()entspricht x and all(c in string.whitespace for c in x)- das dumme führende x andist , warum Sie so oft finden sich Codierung not x or x.isspace(), auf die Einfachheit zurück zu bekommen , die sollte in die entworfen wurden , is...String - Methoden (wobei ein leerer String „ist“ alles , was Sie wollen - im Gegensatz zu man-in-the-Straße Pferde Sinn, vielleicht [[leere Sätze, wie Null & c, haben die meisten Leute immer verwirrt ;-)]], aber voll und ganz dem offensichtlich gut verfeinerten mathematischen gesunden Menschenverstand entsprechend! -).

Alex Martelli
quelle
5

Ich bin mir nicht sicher, nach welcher Antwort Sie suchen? Sie erhalten drei Übereinstimmungen, weil Sie drei Trennzeichen haben. Wenn Sie das nicht möchten, verwenden Sie einfach:

'/segment/segment/'.strip('/').split('/')
Jamieb
quelle
4
-1, weil Sie vier Übereinstimmungen erhalten, nicht drei, und auch dies beantwortet die Frage nicht wirklich.
Roman
1
+1, um dem Negativ entgegenzuwirken. Er sagte nicht, dass Sie drei Ergebnisse zurückbekommen würden. Er sagte "drei Übereinstimmungen" für "drei Trennzeichen", was für mich logisch klingt. Sie erhalten jedoch von nichts "vier Übereinstimmungen". In Ihrem Ergebnis werden jedoch "vier Elemente" zurückgegeben. Außerdem antwortet es nicht direkt auf das "Warum", aber es bietet eine einfache Möglichkeit, das zu bekommen, was er wirklich will ... was meiner Meinung nach keine Ablehnung verdient. Wenn Sie jemanden nicht auswählen wollen (mit einer Gegenstimme, nicht weniger), seien Sie bitte vorsichtiger! Prost! 8 ^)
Kodybrown
@wasatchwizard Danke für die Klarstellung. Ich schätze die Korrektur und die Empfehlung. Leider ist meine Stimme jetzt gesperrt und kann nicht geändert werden.
Roman
Ich liebe deine Lösung - streife dann ab, um das leere Ergebnis zu entfernen
Nam G VU
5

Nun, es lässt Sie wissen, dass es dort ein Trennzeichen gab. Wenn Sie also 4 Ergebnisse sehen, wissen Sie, dass Sie 3 Begrenzer hatten. Auf diese Weise können Sie mit diesen Informationen tun, was Sie möchten, anstatt Python die leeren Elemente löschen zu lassen und dann manuell nach Start- oder Endbegrenzern zu suchen, wenn Sie dies wissen müssen.

Einfaches Beispiel: Angenommen, Sie möchten nach absoluten und relativen Dateinamen suchen. Auf diese Weise können Sie alles mit dem Split erledigen, ohne auch das erste Zeichen Ihres Dateinamens überprüfen zu müssen.

römisch
quelle
1

Betrachten Sie dieses minimale Beispiel:

>>> '/'.split('/')
['', '']

splitmuss dir geben, was vor und nach dem Trennzeichen ist '/', aber es gibt keine anderen Zeichen. Es muss Ihnen also die leere Zeichenfolge geben, die technisch vor und nach der folgt '/', weil '' + '/' + '' == '/'.

timgeb
quelle