Frage Warum gibt "split" bei einer leeren Zeichenfolge ein nicht leeres Array zurück?


Bei einer leeren Zeichenfolge wird ein Array der Größe 1 zurückgegeben:

scala> "".split(',')
res1: Array[String] = Array("")

Beachten Sie, dass dies ein leeres Array zurückgibt:

scala> ",,,,".split(',')
res2: Array[String] = Array()

Bitte erkläre :)


76
2018-02-11 00:50


Ursprung


Antworten:


Aus dem gleichen Grund, dass

",test" split ','

und

",test," split ','

gibt ein Array der Größe 2 zurück. Alles vor der ersten Übereinstimmung wird als erstes Element zurückgegeben.


27
2018-02-11 01:52



Wenn Sie eine Orange Null mal aufteilen, haben Sie genau ein Stück - die Orange.


58
2018-02-11 04:27



Wenn Sie eine leere Zeichenfolge aufteilen, wird die leere Zeichenfolge als erstes Element zurückgegeben. Wenn in der Zielzeichenfolge kein Trennzeichen gefunden wird, erhalten Sie ein Array der Größe 1, das die ursprüngliche Zeichenfolge enthält, selbst wenn es leer ist.


40
2018-02-11 00:55



Die Java und Scala Split-Methoden funktionieren in zwei Schritten:

  • Teilen Sie zuerst die Zeichenfolge durch Trennzeichen. Die natürliche Konsequenz ist, dass, wenn die Zeichenfolge das Trennzeichen nicht enthält, ein Singleton-Array zurückgegeben wird, das nur die Eingabezeichenfolge enthält.
  • Zweite, Entferne alle ganz rechts leeren Strings. Das ist der Grund ",,,".split(",") Gibt ein leeres Array zurück.

Demnach ist das Ergebnis von "".split(",") sollte wegen des zweiten Schrittes ein leeres Array sein, oder?

Es sollte. Leider ist dies ein künstlich eingeführter Eckfall. Und das ist schlimm, aber zumindest es ist dokumentiert im java.util.regex.PatternWenn Sie daran denken, sich die Dokumentation anzusehen:

Für n == 0 ist das Ergebnis wie für n <0, mit Ausnahme von leeren Zeichenketten   wird nicht zurückgegeben. (Beachten Sie, dass der Fall, wenn die Eingabe selbst ein ist   Leerstring ist speziell, wie oben beschrieben, und der Limit-Parameter   gilt dort nicht.)

Lösung 1: Übergeben Sie immer -1 als zweiten Parameter

Also rate ich dir, immer zu bestehen n == -1 als zweiter Parameter (dies überspringt Schritt 2 oben), außer Sie wissen genau, was Sie erreichen wollen / Sie sind sicher, dass die leere Zeichenfolge nicht etwas ist, das Ihr Programm als Eingabe erhalten würde.

TL; DR: Das Aufteilen der leeren Zeichenfolge ist ein künstlich eingeführter Fall, und die Dokumentation warnt Sie davor. Übergeben Sie immer -1 als zweiten Parameter, um Fehler zu vermeiden, es sei denn, Sie haben einen guten Grund.

Lösung 2: Verwenden Sie die Guava Splitter-Klasse

Wenn Sie Guava bereits in Ihrem Projekt verwenden, können Sie das versuchen Splitter (Dokumentation) Klasse. Es hat eine sehr reichhaltige API und macht Ihren Code sehr einfach zu verstehen.

Splitter.on(".").split(".a.b.c.") // "", "a", "b", "c", ""
Splitter.on(",").omitEmptyStrings().split("a,,b,,c") // "a", "b", "c"
Splitter.on(CharMatcher.anyOf(",.")).split("a,b.c") // "a", "b", "c"
Splitter.onPattern("=>?").split("a=b=>c") // "a", "b", "c"
Splitter.on(",").limit(2).split("a,b,c") // "a", "b,c"

25
2018-06-13 18:13



"a".split(",") -> "a" deshalb "".split(",") -> ""


23
2018-04-15 11:06



In allen Programmiersprachen weiß ich, dass ein leerer String immer noch ein gültiger String ist. Wenn Sie also einen Split mit einem Delimiter ausführen, wird immer ein Array mit einem einzelnen Element zurückgegeben, wobei dieses Element der leere String ist. Wenn es ein leerer (nicht leerer) String wäre, wäre das ein anderes Problem.


4
2018-02-11 00:57



Dies split Verhalten wird von Java geerbt, zum Guten oder zum Schlechten ...
Scala überschreibt nicht die Definition von String Primitive.

Beachten Sie, dass Sie das können benutze die limit Argument, um das Verhalten zu ändern:

Der Parameter limit steuert, wie oft das Muster angewendet wird, und beeinflusst daher die Länge des resultierenden Arrays. Wenn das Limit n größer als Null ist, wird das Muster höchstens n - 1 Mal angewendet, die Länge des Arrays ist nicht größer als n und der letzte Eintrag des Arrays enthält alle Eingaben über das letzte übereinstimmende Trennzeichen hinaus. Wenn n nicht positiv ist, wird das Muster so oft wie möglich angewendet und das Array kann eine beliebige Länge haben. Wenn n Null ist, wird das Muster so oft wie möglich angewendet, das Array kann eine beliebige Länge haben, und nachfolgende leere Strings werden verworfen.

d. h., Sie können das einstellen limit=-1 um das Verhalten von (allen?) anderen Sprachen zu bekommen:

@ ",a,,b,,".split(",")
res1: Array[String] = Array("", "a", "", "b")

@ ",a,,b,,".split(",", -1)  // limit=-1
res2: Array[String] = Array("", "a", "", "b", "", "")

Es scheint, dass das Java-Verhalten gut bekannt ist ziemlich verwirrend aber:

Das obige Verhalten kann von mindestens Java 5 bis Java 8 beobachtet werden.

Es wurde versucht, das Verhalten so zu ändern, dass ein leeres Array zurückgegeben wird, wenn eine leere Zeichenfolge in geteilt wird JDK-6559590. Es wurde jedoch bald wieder eingeführt JDK-8028321 wenn es an verschiedenen Orten Regression verursacht. Die Änderung wird es nie in die ursprüngliche Java 8-Version schaffen.

Hinweis: Die Split-Methode war nicht von Anfang an in Java nicht in 1.0.2) ist aber tatsächlich von mindestens 1,4 (z. B. siehe JSR51 circa 2002). Ich untersuche noch ...

Was unklar ist, ist, warum Java dies überhaupt gewählt hat (mein Verdacht ist, dass es ursprünglich ein Versehen / Bug in einem "Randfall" war), aber jetzt unwiderruflich in die Sprache und so gebacken ist bleibt.


1
2017-10-20 04:47