Perché "split" su una stringa vuota restituisce un array non vuoto?


111

La divisione su una stringa vuota restituisce un array di dimensione 1:

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

Considera che questo restituisce un array vuoto:

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

Spiega per favore :)


5
Inoltre, sembra incoerente con il comportamento osservato quando la stringa contiene solo un'istanza del separatore. In questo caso il risultato è effettivamente un array vuoto: ",". Split (","). Length == 0
— LD.

Risposte:


37

Per lo stesso motivo

",test" split ','

e

",test," split ','

restituirà un array di dimensione 2. Tutto ciò che precede la prima corrispondenza viene restituito come primo elemento.


5
La stringa vuota è una stringa, non niente. (ovunque tranne che in Excel)
— Raphael

5
@Raphael O in un database Oracle
— Austin

7
@Raphael, in qualsiasi altro linguaggio di programmazione "".split("wtf").lengthrestituisce 0. Solo in JS è 1.: /
— Andrey Mikhaylov - lolmaus

11
@ DanielC.Sobral Ok, allora perché "," split ","restituisce un array di 0?
— Joan

5
Perché non è tornato tutto dopo l'ultima partita?
— Didier A.

72

Se dividi un'arancia zero volte, hai esattamente un pezzo: l'arancia.


8
Ma l'arancia non è vuota (idk se questo è ciò che significava oluies), è un'arancia. Magari dividendo un'arancia che dovrebbe essere lì, ma non lo è, quindi ottieni un singolo valore: uno spazio vuoto xD
— Nick Rolando

8
Questa è una conversazione profonda.

31
Questa metafora ha senso "orange".split(','), ma non è ovviamente rilevante per dividere stringhe vuote. Se divido zero volte la mia mancanza di arancione, non ho ancora l'arancia; lo rappresentiamo come una lista vuota di arance senza arance, una lista di esattamente una senza arance, una lista di dodici senza arance o cosa? Non è una questione di cosa ci ritroviamo, ma di come lo rappresentiamo.
— Matchu

1
Ma se dividi un libro inesistente per le sue pagine, non otterrai nulla.
— SMUsamaShah

49

I metodi split Java e Scala funzionano in due passaggi come questo:

  • Per prima cosa, dividi la stringa per delimitatore. La conseguenza naturale è che se la stringa non contiene il delimitatore, viene restituito un array singleton contenente solo la stringa di input,
  • In secondo luogo, rimuovere tutte le stringhe vuote più a destra. Questo è il motivo per cui ",,,".split(",")restituisce un array vuoto.

In base a ciò, il risultato di "".split(",")dovrebbe essere un array vuoto a causa del secondo passaggio, giusto?

Dovrebbe. Sfortunatamente, questo è un caso d'angolo introdotto artificialmente. E questo è male, ma almeno è documentato in java.util.regex.Pattern, se vi ricordate di dare un'occhiata alla documentazione:

Per n == 0, il risultato è come per n <0, tranne per il fatto che le stringhe vuote finali non verranno restituite. (Si noti che il caso in cui l'input è esso stesso una stringa vuota è speciale, come descritto sopra, e il parametro limit non si applica qui.)

Soluzione 1: passare sempre -1 come secondo parametro

Quindi, ti consiglio di passare sempre n == -1 come secondo parametro (questo salterà il passaggio due sopra), a meno che tu non sappia specificamente cosa vuoi ottenere / sei sicuro che la stringa vuota non è qualcosa che il tuo programma otterrebbe come input.

Soluzione 2: utilizzare la classe Guava Splitter

Se stai già usando Guava nel tuo progetto, puoi provare la classe Splitter (documentazione) . Ha un'API molto ricca e rende il tuo codice molto facile da capire.

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"

1
+1, questa è l'unica risposta che effettivamente cita la documentazione e fa notare che è incoerente. Tuttavia, non ho trovato la parte evidenziata del commento nel mio JavaDoc.
— Yogu

L'ho trovato in java.util.regex.Pattern, ma sembra quasi sparito. Al momento della scrittura, era sicuramente presente nell'albero dei sorgenti di OpenJDK ufficiale come javadoc. android.googlesource.com/platform/libcore/+/… Forse dovremmo segnalare un bug?
— Rok Kralj

Sarebbe una buona idea segnalare un bug: il comportamento sicuramente non verrà modificato, ma dovrebbe almeno essere documentato.
— Yogu

@RokKralj Android non utilizzava la libreria OpenJDK, ma era invece basata su Apache Harmony, quindi forse stai cercando nel posto sbagliato?
— lxgr

1
"".split (",", n)genera un array di un elemento per n in (-1, 0, 1) con Oracle JDK 8. Sarebbe bello ottenere solo un elenco di token non vuoti - suppongo che una regex completa potrebbe essere necessaria (qualcosa di simile "[^,\\s]+[^,]*[^,\\s]*").
— simon.watts

40

La divisione di una stringa vuota restituisce la stringa vuota come primo elemento. Se non viene trovato alcun delimitatore nella stringa di destinazione, otterrai un array di dimensione 1 che contiene la stringa originale, anche se è vuoto.


2
Sbagliato. Split rimuove tutte le stringhe vuote più a destra, quindi il risultato dovrebbe essere un array vuoto. Vedi la mia risposta. ",".split(",")restituisce un array vuoto.
— Rok Kralj

23

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


6
Sbagliato. Split rimuove tutte le stringhe vuote più a destra, quindi il risultato dovrebbe essere un array vuoto. Vedi la mia risposta. ",".split(",")restituisce un array vuoto.
— Rok Kralj

5

In tutti i linguaggi di programmazione so che una stringa vuota è ancora una stringa valida. Quindi eseguire una divisione utilizzando qualsiasi delimitatore restituirà sempre un singolo array di elementi in cui quell'elemento è la stringa vuota. Se fosse una stringa nulla (non vuota), sarebbe un problema diverso.


Penso che questa sia una funzione di libreria e non una parte del linguaggio. Ad esempio in google guava potresti omettere stringhe vuote. > Iterable <String> pieces = com.google.common.base.Splitter.on (','). OmitEmptyStrings (). Split ("");
— oluies

2

Questo splitcomportamento è ereditato da Java, nel bene e nel male ...
Scala non sovrascrive la definizione del fileString primitiva.

Nota che puoi usare l' limitargomento per modificare il comportamento :

Il parametro limit controlla il numero di volte in cui il pattern viene applicato e quindi influisce sulla lunghezza della matrice risultante. Se il limite n è maggiore di zero, il modello verrà applicato al massimo n - 1 volte, la lunghezza dell'array non sarà maggiore di n e l'ultima voce dell'array conterrà tutto l'input oltre l'ultimo delimitatore corrispondente. Se n è non positivo, il pattern verrà applicato il maggior numero di volte possibile e l'array può avere qualsiasi lunghezza. Se n è zero, il modello verrà applicato quante più volte possibile, l'array può avere qualsiasi lunghezza e le stringhe vuote finali verranno scartate.

cioè puoi impostare il limit=-1per ottenere il comportamento di (tutte?) le altre lingue:

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

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

Sembra essere noto che il comportamento di Java è abbastanza confuso ma:

Il comportamento sopra può essere osservato almeno da Java 5 a Java 8.

Si è verificato un tentativo di modificare il comportamento per restituire un array vuoto durante la divisione di una stringa vuota in JDK-6559590 . Tuttavia, è stato presto ripristinato in JDK-8028321 quando causa la regressione in vari punti. La modifica non è mai stata introdotta nella versione iniziale di Java 8.

Nota: il metodo split non era in Java dall'inizio ( non è in 1.0.2 ) ma in realtà è presente almeno dalla 1.4 (ad esempio, vedere JSR51 circa 2002). Sto ancora indagando ...

Ciò che non è chiaro è il motivo per cui Java ha scelto questo in primo luogo (il mio sospetto è che originariamente fosse una svista / bug in un "caso limite"), ma ora irrevocabilmente inserito nel linguaggio e così rimane .


Non sono sicuro che questo risponda alla domanda - sebbene possa essere vero per l'esempio fornito qui, non aiuta con il caso della stringa vuota - "".split(",")restituisce comunque un singolo array di elementi come [""].
— DaveyDaveDave

@DaveyDaveDave che è il comportamento previsto di ogni altra lingua. Il ",,,," è il comportamento bizzarro / diverso in Scala, e diverso dal caso "".
— Andy Hayden

0

Le stringhe vuote non hanno uno stato speciale durante la divisione di una stringa. Puoi usare:

Some(str)
  .filter(_ != "")
  .map(_.split(","))
  .getOrElse(Array())
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.