Le comportement de String.split
(qui appelle Pattern.split
) change entre Java 7 et Java 8.
Documentation
En comparant la documentation de Pattern.split
dans Java 7 et Java 8 , nous observons l'ajout de la clause suivante:
Lorsqu'il existe une correspondance de largeur positive au début de la séquence d'entrée, une sous-chaîne de début vide est incluse au début du tableau résultant. Une correspondance de largeur nulle au début ne produit cependant jamais une telle sous-chaîne de début vide.
La même clause est également ajoutée String.split
dans Java 8 , par rapport à Java 7 .
Implémentation de référence
Comparons le code de Pattern.split
l'implémentation de référence en Java 7 et Java 8. Le code est récupéré depuis grepcode, pour les versions 7u40-b43 et 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);
}
L'ajout du code suivant dans Java 8 exclut la correspondance de longueur nulle au début de la chaîne d'entrée, ce qui explique le comportement ci-dessus.
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;
}
Maintenir la compatibilité
Comportement suivant dans Java 8 et supérieur
Pour rendre le split
comportement cohérent entre les versions et compatible avec le comportement de Java 8:
- Si votre expression régulière peut correspondre à une chaîne de longueur nulle, ajoutez simplement
(?!\A)
à la fin de l'expression régulière et enveloppez l'expression régulière d'origine dans un groupe non capturant (?:...)
(si nécessaire).
- Si votre expression régulière ne peut pas correspondre à une chaîne de longueur nulle, vous n'avez rien à faire.
- Si vous ne savez pas si l'expression régulière peut correspondre à une chaîne de longueur nulle ou non, effectuez les deux actions de l'étape 1.
(?!\A)
vérifie que la chaîne ne se termine pas au début de la chaîne, ce qui implique que la correspondance est une correspondance vide au début de la chaîne.
Comportement suivant dans Java 7 et antérieurs
Il n'y a pas de solution générale pour rendre la split
compatibilité descendante avec Java 7 et les versions antérieures, à moins de remplacer toutes les instances de split
pour pointer vers votre propre implémentation personnalisée.
s.split("(?!^)")
semble fonctionner.