Der folgende Code wird sowohl in Java 8 als auch in Java kompiliert, verhält sich jedoch unterschiedlich.
class Simple {
static String sample = "\nEn un lugar\r\nde la Mancha\nde cuyo nombre\r\nno quiero acordarme";
public static void main(String args[]){
String[] chunks = sample.split("\\R\\R");
for (String chunk: chunks) {
System.out.println("Chunk : "+chunk);
}
}
}
Wenn ich es mit Java 8 ausführe, wird Folgendes zurückgegeben:
Chunk :
En un lugar
de la Mancha
de cuyo nombre
no quiero acordarme
Aber wenn ich es mit Java 9 ausführe, ist die Ausgabe anders:
Chunk :
En un lugar
Chunk : de la Mancha
de cuyo nombre
Chunk : no quiero acordarme
Warum?
\R
gierig, in 9 nicht.System.getProperty("line.separator")
?\R
ist der Linebreak Matcher . Es wird mit allem übereinstimmen, was das OP dort hat.\R
, da es verboten ist, nur eine CR abzugleichen, wenn LF folgt. Eine andere Möglichkeit, dies auszudrücken, besteht darin, dass es nicht zurückverfolgt werden kann. Java 8 war korrekt; Soweit ich das beurteilen kann, stimmt Java 9 jetzt nicht mehr mit tr18 überein.Antworten:
Die Java-Dokumentation stimmt nicht mit dem Unicode-Standard überein. Der Javadoc nebelt, was
\R
passen soll. Es liest:Diese Java-Dokumentation ist fehlerhaft. In seinem Abschnitt zu Zeilenumbrüchen R1.6 stellt der Unicode Technical Standard Nr. 18 für reguläre Ausdrücke klar fest:
Mit anderen Worten, es kann nur eine CR + LF-Sequenz (Wagenrücklauf + Zeilenvorschub) mit zwei Codepunkten oder ein einzelner Codepunkt aus dieser Menge übereinstimmen , vorausgesetzt, es handelt sich nicht nur um einen Wagenrücklauf allein, dem dann ein Zeilenvorschub folgt . Das liegt daran, dass es nicht erlaubt ist, zu sichern . CRLF muss atomar sein, damit
\R
es richtig funktioniert.Java 9 entspricht also nicht mehr den Empfehlungen von R1.6. Außerdem macht es jetzt etwas, was es in Java 8 NICHT tun sollte und nicht tat.
Es scheint an der Zeit zu sein, dass ich Sherman (sprich: Xueming Shen) wieder einen Schrei gebe. Ich habe schon früher mit ihm an diesen wichtigen Fragen der formalen Konformität gearbeitet.
quelle
(?>\\R)
oder\\R{1}+
anstelle von\\R
oder im speziellen Fall des OP\\R{2}+
anstelle von zu verwenden\\R\\R
. Interessanterweise sogar\\R{1}\\R{1}
oder\\R{2}
geben Sie das gewünschte Ergebnis unter Java 9, was inkonsistent ist, da der Nicht-Possessiv{n}
das Back-Tracking nicht deaktivieren sollte.Es war ein Fehler in Java 8 und wurde behoben: JDK-8176029: "Linebreak Matcher entspricht nicht dem in Javadoc angegebenen Muster" .
Siehe auch: Negatives Aussehen von Java-8-Regex mit `\ R`
quelle
replaceAll ("\\R", "\\n")
(nicht getestet, aber ich würde vermuten, dass Änderungen beim Zurückverfolgen hier keine Rolle spielen).\R
soll nicht zurückverfolgt werden können; Dafür gibt es gute Gründe. Ich werde sehen, was ich finden kann: Sie dürfen eine CRLF niemals in zwei Instanzen aufteilen oder\R
.