¿Por qué "dividir" en una cadena vacía devuelve una matriz no vacía?


111

Dividir en una cadena vacía devuelve una matriz de tamaño 1:

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

Considere que esto devuelve una matriz vacía:

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

Por favor explique :)


5
Además, parece inconsistente con el comportamiento observado cuando la cadena contiene solo una instancia del separador. En este caso, el resultado es efectivamente una matriz vacía: ",". Split (","). Length == 0
LD.

Respuestas:


37

Por la misma razón que

",test" split ','

y

",test," split ','

devolverá una matriz de tamaño 2. Todo lo anterior a la primera coincidencia se devuelve como primer elemento.


5
La cadena vacía es una cadena, no nada. (en cualquier lugar menos en Excel)
Raphael

5
@Raphael O en una base de datos Oracle
Austin

7
@Raphael, en cualquier otro lenguaje de programación "".split("wtf").lengthdevuelve 0. Solo en JS es 1.: /
Andrey Mikhaylov - lolmaus

11
@ DanielC.Sobral Ok, entonces ¿por qué "," split ","devuelve una matriz de 0?
Joan

5
¿Por qué no regresó todo después del último partido?
Didier A.

72

Si divide una naranja por cero, tiene exactamente una pieza: la naranja.


8
Pero la naranja no está vacía (no sé si eso es lo que significa oluies), es una naranja. Tal vez dividiendo una naranja que debería estar allí, pero no lo está, para obtener un valor único: un espacio vacío xD
Nick Rolando

8
Esta es una conversación profunda.

31
Esta metáfora tiene sentido "orange".split(','), pero obviamente no es relevante para dividir cadenas vacías. Si divido mi falta de naranja en cero veces, todavía no tengo naranja; ¿Representamos eso como una lista vacía de no-naranjas, una lista de exactamente una no-naranja, una lista de doce no-naranjas, o qué? No se trata de con qué terminamos, sino de cómo lo representamos.
Matchu

1
Pero si divide un libro inexistente por sus páginas, no obtendrá nada.
SMUsamaShah

49

Los métodos de división de Java y Scala operan en dos pasos como este:

  • Primero, divida la cadena por delimitador. La consecuencia natural es que si la cadena no contiene el delimitador, se devuelve una matriz singleton que contiene solo la cadena de entrada,
  • En segundo lugar, elimine todas las cadenas vacías más a la derecha. Esta es la razón por la que ",,,".split(",")devuelve una matriz vacía.

De acuerdo con esto, el resultado de "".split(",")debería ser una matriz vacía debido al segundo paso, ¿verdad?

Debería. Desafortunadamente, este es un caso de esquina introducido artificialmente. Y eso es malo, pero al menos está documentado en java.util.regex.Pattern, si recuerdas echarle un vistazo a la documentación:

Para n == 0, el resultado es como para n <0, excepto que no se devolverán cadenas vacías al final. (Tenga en cuenta que el caso en el que la entrada es en sí misma una cadena vacía es especial, como se describe anteriormente, y el parámetro de límite no se aplica allí).

Solución 1: pase siempre -1 como segundo parámetro

Por lo tanto, le aconsejo que siempre pase n == -1como el segundo parámetro (esto omitirá el paso dos anterior), a menos que sepa específicamente lo que desea lograr / esté seguro de que la cadena vacía no es algo que su programa obtendría como entrada.

Solución 2: use la clase Guava Splitter

Si ya está utilizando Guava en su proyecto, puede probar la clase Splitter (documentación) . Tiene una API muy rica y hace que su código sea muy fácil de entender.

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, esta es la única respuesta que realmente cita la documentación y señala que es inconsistente. Sin embargo, no encontré la parte resaltada del comentario en mi JavaDoc.
Yogu

Lo encontré en java.util.regex.Pattern, pero parece que ya no está. En el momento de escribir este artículo, definitivamente estaba presente en el árbol de fuentes oficial de OpenJDK como un javadoc. android.googlesource.com/platform/libcore/+/… ¿ Quizás deberíamos informar un error?
Rok Kralj

Sería una buena idea informar de un error; el comportamiento definitivamente no se cambiará, pero al menos debería estar documentado.
Yogu

@RokKralj Android no usó la biblioteca OpenJDK, sino que se basó en Apache Harmony, por lo que tal vez esté buscando en el lugar equivocado.
lxgr

1
"".split (",", n)genera una matriz de un elemento para n en (-1, 0, 1) con Oracle JDK 8. Sería bueno obtener una lista de tokens no vacíos solamente - supongo que puede ser necesaria una expresión regular completa (algo así como "[^,\\s]+[^,]*[^,\\s]*").
simon.watts

40

Dividir una cadena vacía devuelve la cadena vacía como primer elemento. Si no se encuentra un delimitador en la cadena de destino, obtendrá una matriz de tamaño 1 que contiene la cadena original, incluso si está vacía.


2
Incorrecto. Dividir elimina todas las cadenas vacías del extremo derecho, por lo que el resultado debería ser una matriz vacía. Mira mi respuesta. ",".split(",")devuelve una matriz vacía.
Rok Kralj

23

"a".split(",")-> "a" por tanto "".split(",")->""


6
Incorrecto. Dividir elimina todas las cadenas vacías del extremo derecho, por lo que el resultado debería ser una matriz vacía. Mira mi respuesta. ",".split(",")devuelve una matriz vacía.
Rok Kralj

5

En todos los lenguajes de programación, sé que una cadena en blanco sigue siendo una cadena válida. Entonces, hacer una división usando cualquier delimitador siempre devolverá una matriz de un solo elemento donde ese elemento es la Cadena en blanco. Si fuera una cadena nula (no en blanco), entonces sería un problema diferente.


Creo que esta es una función de la biblioteca y no parte del lenguaje. Por ejemplo, en google guava puede omitir cadenas vacías. > Iterable <String> pieces = com.google.common.base.Splitter.on (','). OmitEmptyStrings (). Split ("");
oluies

2

Este splitcomportamiento se hereda de Java, para bien o para mal ...
Scala no anula la definición de la Stringprimitiva.

Tenga en cuenta que puede usar el limitargumento para modificar el comportamiento :

El parámetro de límite controla el número de veces que se aplica el patrón y, por lo tanto, afecta la longitud de la matriz resultante. Si el límite n es mayor que cero, entonces el patrón se aplicará como máximo n - 1 veces, la longitud de la matriz no será mayor que n, y la última entrada de la matriz contendrá todas las entradas más allá del último delimitador coincidente. Si n no es positivo, el patrón se aplicará tantas veces como sea posible y la matriz puede tener cualquier longitud. Si n es cero, el patrón se aplicará tantas veces como sea posible, la matriz puede tener cualquier longitud y las cadenas vacías finales se descartarán.

es decir, puede configurar el limit=-1para obtener el comportamiento de (¿todos?) otros idiomas:

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

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

Parece ser bien sabido que el comportamiento de Java es bastante confuso, pero:

El comportamiento anterior se puede observar desde al menos Java 5 hasta Java 8.

Se intentó cambiar el comportamiento para devolver una matriz vacía al dividir una cadena vacía en JDK-6559590 . Sin embargo, pronto se revirtió en JDK-8028321 cuando causa regresión en varios lugares. El cambio nunca llega a la versión inicial de Java 8.

Nota: El método de división no estaba en Java desde el principio (no está en 1.0.2 ) pero en realidad está ahí desde al menos 1.4 (por ejemplo, ver JSR51 alrededor de 2002). Sigo investigando ...

Lo que no está claro es por qué Java eligió esto en primer lugar (mi sospecha es que originalmente fue un descuido / error en un "caso marginal"), pero ahora irrevocablemente integrado en el lenguaje y así permanece .


No estoy seguro de que esto responda a la pregunta; si bien puede ser cierto para el ejemplo que se da aquí, no ayuda con el caso de la cadena vacía, "".split(",")todavía devuelve una matriz de un solo elemento como [""].
DaveyDaveDave

@DaveyDaveDave ese es el comportamiento esperado de todos los demás idiomas. El ",,,," es el comportamiento extraño / diferente en Scala, y diferente al caso "".
Andy Hayden

0

La cadena vacía no tiene un estado especial al dividir una cadena. Puedes utilizar:

Some(str)
  .filter(_ != "")
  .map(_.split(","))
  .getOrElse(Array())
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.