O comportamento de String.split
(que chama Pattern.split
) muda entre Java 7 e Java 8.
Documentação
Comparando entre a documentação de Pattern.split
em Java 7 e Java 8 , observamos a seguinte cláusula que está sendo adicionado:
Quando há uma correspondência de largura positiva no início da sequência de entrada, uma substring inicial vazia é incluída no início da matriz resultante. Uma correspondência de largura zero no início, entretanto, nunca produz essa substring inicial vazia.
A mesma cláusula também é adicionada String.split
no Java 8 , em comparação com o Java 7 .
Implementação de referência
Vamos comparar o código da Pattern.split
implementação de referência em Java 7 e Java 8. O código é recuperado de grepcode, para as versões 7u40-b43 e 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);
}
A adição do código a seguir em Java 8 exclui a correspondência de comprimento zero no início da string de entrada, o que explica o comportamento acima.
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;
}
Manter a compatibilidade
Seguindo o comportamento no Java 8 e superior
Para tornar o split
comportamento consistente entre as versões e compatível com o comportamento em Java 8:
- Se sua regex pode corresponder a uma string de comprimento zero, basta adicionar
(?!\A)
no final da regex e envolver a regex original no grupo de não captura (?:...)
(se necessário).
- Se sua regex não pode corresponder a uma string de comprimento zero, você não precisa fazer nada.
- Se você não sabe se a regex pode corresponder a uma string de comprimento zero ou não, execute as duas ações da etapa 1.
(?!\A)
verifica se a string não termina no início da string, o que implica que a correspondência é uma correspondência vazia no início da string.
Seguindo o comportamento em Java 7 e anteriores
Não há uma solução geral para tornar split
compatível com versões anteriores do Java 7 e anteriores, exceto substituir todas as instâncias de split
para apontar para sua própria implementação customizada.
s.split("(?!^)")
parece funcionar.