La división de cadenas de Java eliminó los valores vacíos

286

Estoy tratando de dividir el valor usando un separador. Pero estoy encontrando los resultados sorprendentes

String data = "5|6|7||8|9||";
String[] split = data.split("\\|");
System.out.println(split.length);

Espero obtener 8 valores. [5,6,7, VACÍO, 8,9, VACÍO, VACÍO] Pero solo obtengo 6 valores.

Cualquier idea y cómo solucionarlo. No importa si el valor VACÍO se encuentra en cualquier lugar, debe estar en la matriz.

Reddy
fuente

Respuestas:

492

split(delimiter)de forma predeterminada, elimina las cadenas vacías finales de la matriz de resultados. Para desactivar este mecanismo, necesitamos usar una versión sobrecargada de split(delimiter, limit)con limitun valor negativo como

String[] split = data.split("\\|", -1);

Un poco más de detalles:
split(regex)devuelve internamente el resultado split(regex, 0)y la documentación de este método que puede encontrar (énfasis mío)

El limitparámetro controla la cantidad de veces que se aplica el patrón y, por lo tanto, afecta la longitud de la matriz resultante.

Si el límite nes mayor que cero , 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 non es positivo , el patrón se aplicará tantas veces como sea posible y la matriz puede tener cualquier longitud.

Si nes 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 .

excepción :

Vale la pena mencionar que eliminar la cadena vacía final tiene sentido solo si dichas cadenas vacías se crean mediante un mecanismo dividido . Entonces, "".split(anything)dado que no podemos dividirnos ""más, obtendremos como [""]matriz de resultados .
Ocurre porque la división no ocurrió aquí, por lo que a ""pesar de estar vacío y el final representa la cadena original , no la cadena vacía que se creó mediante el proceso de división.

jlordo
fuente
2
Guau. eso funcionó brillantemente. pero -1 ¿cómo esto lo cambia todo?
Reddy
1
incluso puedes probar condata.split("\\|", 8)
Subhrajyoti Majumder
23
¡No lo uses split("\\|", 8)porque esto limita a las primeras ocho fichas! Si su cadena es variable, debe usarla split("\\|", -1)para que cree un número ilimitado de tokens y no descarte los tokens vacíos al final.
ADTC
2
@Reddy -1 ( o cualquier número negativo de hecho, no importa cuál sea el valor absoluto ) le dice al método de división que mantenga los tokens vacíos al final. El valor predeterminado es 0, que le dice al método que descarte los tokens vacíos al final de la matriz.
ADTC
8
Aparentemente, mucha gente esperaba que mantener las cadenas vacías finales es la funcionalidad predeterminada para split(regex). Terminaron aquí y descubrieron que no lo es.
Attila Tanyi
32

De la documentación de String.split(String regex):

Este método funciona como si invocara el método de división de dos argumentos con la expresión dada y un argumento límite de cero. Por lo tanto, las cadenas vacías finales no se incluyen en la matriz resultante.

Entonces tendrá que usar la versión de dos argumentos String.split(String regex, int limit)con un valor negativo:

String[] split = data.split("\\|",-1);

Doc:

Si el límite n es mayor que cero, 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.

Esto no dejará fuera ningún elemento vacío, incluidos los finales.

ppeterka
fuente
4

De String.split () API Doc :

Divide esta cadena alrededor de coincidencias de la expresión regular dada. Este método funciona como si invocara el método de división de dos argumentos con la expresión dada y un argumento límite de cero. Por lo tanto, las cadenas vacías finales no se incluyen en la matriz resultante.

String.split sobrecargado (regex, int) es más apropiado para su caso.

PermGenError
fuente
1
Eso explica el comportamiento pero no responde la pregunta.
Assylias
@assylias lo agregó a mi respuesta ahora :)
PermGenError
4

String[] split = data.split("\\|",-1);

Este no es el requisito real en todo momento. El inconveniente de lo anterior se muestra a continuación:

Scenerio 1:
When all data are present:
    String data = "5|6|7||8|9|10|";
    String[] split = data.split("\\|");
    String[] splt = data.split("\\|",-1);
    System.out.println(split.length); //output: 7
    System.out.println(splt.length); //output: 8

Cuando faltan datos:

Scenerio 2: Data Missing
    String data = "5|6|7||8|||";
    String[] split = data.split("\\|");
    String[] splt = data.split("\\|",-1);
    System.out.println(split.length); //output: 5
    System.out.println(splt.length); //output: 8

El requisito real es que la longitud debe ser 7, aunque faltan datos. Porque hay casos como cuando necesito insertar en la base de datos o algo más. Podemos lograr esto usando el siguiente enfoque.

    String data = "5|6|7||8|||";
    String[] split = data.split("\\|");
    String[] splt = data.replaceAll("\\|$","").split("\\|",-1);
    System.out.println(split.length); //output: 5
    System.out.println(splt.length); //output:7

Lo que he hecho aquí es que estoy eliminando "|" tubería al final y luego dividiendo la cadena. Si tiene "," como separador, entonces necesita agregar ", $" dentro de replaceAll.

Yanish Pradhananga
fuente
1

puede tener varios separadores, incluidos espacios en blanco, comas, punto y coma, etc.

 String[] tokens = "a , b,  ,c; ;d,      ".split( "[,; \t\n\r]+" );

tendrás 4 fichas: a, b, c, d

los separadores iniciales en la cadena de origen deben eliminarse antes de aplicar esta división.

como respuesta a la pregunta formulada:

String data = "5|6|7||8|9||";
String[] split = data.split("[\\| \t\n\r]+");

espacios en blanco agregados por si acaso los tendrá como separadores junto con |

Dmitriy Pichugin
fuente