El comportamiento de String.split
(qué llamadas Pattern.split
) cambia entre Java 7 y Java 8.
Documentación
Comparando entre la documentación de Pattern.split
en Java 7 y Java 8 , se observa la siguiente cláusula se añade:
Cuando hay una coincidencia de ancho positivo al comienzo de la secuencia de entrada, se incluye una subcadena principal vacía al comienzo de la matriz resultante. Sin embargo, una coincidencia de ancho cero al principio nunca produce una subcadena inicial vacía.
La misma cláusula también se agrega String.split
en Java 8 , en comparación con Java 7 .
Implementación de referencia
Comparemos el código de Pattern.split
la implementación de referencia en Java 7 y Java 8. El código se recupera de grepcode, para la versión 7u40-b43 y 8-b132.
Java 7
public String[] split(CharSequence input, int limit) {
int index = 0;
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<>();
Matcher m = matcher(input);
// Add segments before each match found
while(m.find()) {
if (!matchLimited || matchList.size() < limit - 1) {
String match = input.subSequence(index, m.start()).toString();
matchList.add(match);
index = m.end();
} else if (matchList.size() == limit - 1) { // last one
String match = input.subSequence(index,
input.length()).toString();
matchList.add(match);
index = m.end();
}
}
// If no match was found, return this
if (index == 0)
return new String[] {input.toString()};
// Add remaining segment
if (!matchLimited || matchList.size() < limit)
matchList.add(input.subSequence(index, input.length()).toString());
// Construct result
int resultSize = matchList.size();
if (limit == 0)
while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
resultSize--;
String[] result = new String[resultSize];
return matchList.subList(0, resultSize).toArray(result);
}
Java 8
public String[] split(CharSequence input, int limit) {
int index = 0;
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<>();
Matcher m = matcher(input);
// Add segments before each match found
while(m.find()) {
if (!matchLimited || matchList.size() < limit - 1) {
if (index == 0 && index == m.start() && m.start() == m.end()) {
// no empty leading substring included for zero-width match
// at the beginning of the input char sequence.
continue;
}
String match = input.subSequence(index, m.start()).toString();
matchList.add(match);
index = m.end();
} else if (matchList.size() == limit - 1) { // last one
String match = input.subSequence(index,
input.length()).toString();
matchList.add(match);
index = m.end();
}
}
// If no match was found, return this
if (index == 0)
return new String[] {input.toString()};
// Add remaining segment
if (!matchLimited || matchList.size() < limit)
matchList.add(input.subSequence(index, input.length()).toString());
// Construct result
int resultSize = matchList.size();
if (limit == 0)
while (resultSize > 0 && matchList.get(resultSize-1).equals(""))
resultSize--;
String[] result = new String[resultSize];
return matchList.subList(0, resultSize).toArray(result);
}
La adición del siguiente código en Java 8 excluye la coincidencia de longitud cero al comienzo de la cadena de entrada, lo que explica el comportamiento anterior.
if (index == 0 && index == m.start() && m.start() == m.end()) {
// no empty leading substring included for zero-width match
// at the beginning of the input char sequence.
continue;
}
Mantener la compatibilidad
Siguiendo el comportamiento en Java 8 y superior
Para que se split
comporte de manera uniforme en todas las versiones y sea compatible con el comportamiento en Java 8:
- Si su expresión regular puede coincidir con una cadena de longitud cero, simplemente agregue
(?!\A)
al final de la expresión regular y envuelva la expresión regular original en el grupo que no captura (?:...)
(si es necesario).
- Si su expresión regular no puede coincidir con una cadena de longitud cero, no necesita hacer nada.
- Si no sabe si la expresión regular puede coincidir con una cadena de longitud cero o no, realice ambas acciones en el paso 1.
(?!\A)
comprueba que la cadena no termine al principio de la cadena, lo que implica que la coincidencia es una coincidencia vacía al principio de la cadena.
Siguiendo el comportamiento en Java 7 y anteriores
No existe una solución general para hacer split
compatible con versiones anteriores de Java 7 y versiones anteriores, salvo reemplazar todas las instancias de split
para que apunten a su propia implementación personalizada.
s.split("(?!^)")
parece funcionar.