Das Verhalten von String.split
(welches aufruft Pattern.split
) ändert sich zwischen Java 7 und Java 8.
Dokumentation
Beim Vergleich zwischen der Dokumentation Pattern.split
in Java 7 und Java 8 wird die folgende Klausel hinzugefügt:
Wenn zu Beginn der Eingabesequenz eine Übereinstimmung mit positiver Breite vorliegt, wird am Anfang des resultierenden Arrays eine leere führende Teilzeichenfolge eingefügt. Eine Übereinstimmung mit der Breite Null am Anfang erzeugt jedoch niemals einen solchen leeren führenden Teilstring.
Dieselbe Klausel wird auch String.split
in Java 8 im Vergleich zu Java 7 hinzugefügt .
Referenzimplementierung
Vergleichen wir den Code Pattern.split
der Referenzimplemetation in Java 7 und Java 8. Der Code wird aus grepcode für die Versionen 7u40-b43 und 8-b132 abgerufen.
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);
}
Das Hinzufügen des folgenden Codes in Java 8 schließt die Übereinstimmung mit der Länge Null am Anfang der Eingabezeichenfolge aus, was das obige Verhalten erklärt.
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;
}
Kompatibilität aufrechterhalten
Folgendes Verhalten in Java 8 und höher
So split
verhalten Sie sich über Versionen hinweg konsistent und mit dem Verhalten in Java 8 kompatibel:
- Wenn Ihre Regex mit einer Zeichenfolge mit der Länge Null übereinstimmen kann , fügen Sie sie einfach
(?!\A)
am Ende der Regex hinzu und verpacken Sie die ursprüngliche Regex in eine nicht erfassende Gruppe (?:...)
(falls erforderlich).
- Wenn Ihre Regex nicht mit einer Zeichenfolge mit der Länge Null übereinstimmen kann, müssen Sie nichts tun.
- Wenn Sie nicht wissen, ob der reguläre Ausdruck mit einer Zeichenfolge mit der Länge Null übereinstimmen kann, führen Sie beide Aktionen in Schritt 1 aus.
(?!\A)
Überprüft, ob die Zeichenfolge nicht am Anfang der Zeichenfolge endet. Dies bedeutet, dass die Übereinstimmung am Anfang der Zeichenfolge eine leere Übereinstimmung ist.
Folgendes Verhalten in Java 7 und früher
Es gibt keine allgemeine Lösung, um die split
Abwärtskompatibilität mit Java 7 und früheren Versionen zu gewährleisten, ohne alle Instanzen von split
zu ersetzen , um auf Ihre eigene benutzerdefinierte Implementierung zu verweisen.
s.split("(?!^)")
scheint zu funktionieren.