Der folgende Code lässt sich sowohl in Java 8 als auch in 9 kompilieren, verhält sich jedoch anders.
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, gibt es Folgendes zurück:
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
Wieso den?
Es war ein Fehler in Java 8 und er wurde behoben: JDK-8176029: „Der Zeilenumbruch-Matcher entspricht nicht dem in Javadoc angegebenen Muster“.
Siehe auch: Java-8 Regex negatives Lookbehind mit `\R`
Das Java-Dokumentation entspricht nicht dem Unicode-Standard. Das Javadoc verwechselt was \R
soll passen. Es liest:
\R
Jede Unicode-Zeilenumbruchsequenz ist äquivalent zu \u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]
Diese Java-Dokumentation ist fehlerhaft. In seinem Abschnitt zu R1.6 Zeilenumbrüchen, Technischer Unicode-Standard Nr. 18 zu regulären Ausdrücken klar sagt:
Es wird dringend empfohlen, dass ein Metazeichen für reguläre Ausdrücke vorhanden ist, z. B. “\R”, um alle oben aufgeführten Zeilenendezeichen und Sequenzen (z. B. in #1) abzugleichen. Dies würde dem folgenden Ausdruck entsprechen. Dieser Ausdruck wird durch die Notwendigkeit, Backups zu vermeiden, etwas verkompliziert.
(?:\u{D A}|(?!\u{D A})[\u{A}-\u{D}\u{85}\u{2028}\u{2029}]
Mit anderen Worten, es kann nur mit einer CR+LF-Sequenz (Wagenrücklauf + Zeilenvorschub) mit zwei Codepunkten übereinstimmen oder aber ein einzelner Codepunkt aus diesem Satz, sofern dies der Fall ist nicht nur ein Wagenrücklauf allein, dem dann ein Zeilenvorschub folgt. Das ist, weil es ist darf nicht sichern. CRLF muss für atomar sein \R
um richtig zu funktionieren.
Java 9 entspricht also nicht mehr dem, was R1.6 dringend empfiehlt. Darüber hinaus tut es jetzt etwas, was es in Java 8 NICHT tun sollte und nicht getan hat.
Sieht so aus, als wäre es Zeit für mich, Sherman (sprich: Xueming Shen) noch einmal zu brüllen. Ich habe schon früher mit ihm an diesen wesentlichen Fragen der formellen Konformität gearbeitet.
Sieht aus wie in Java 8
\R
ist gierig, während es in 9 nicht der Fall ist.– Benutzer319799
18. Dezember 2017 um 16:02 Uhr
Aus welcher Saite kommst du
System.getProperty("line.separator")
?– Sergej Kalinitschenko
18. Dezember 2017 um 16:06 Uhr
@dasblinkenlight: Das sollte keine Rolle spielen;
\R
ist der Linebreak-Matcher. Es passt zu allem, was das OP dort hat.– Makoto
18. Dezember 2017 um 16:08 Uhr
Wenn Sie diese Art von Frage stellen, lohnt es sich, die JDK-Versionsnummern anzugeben, da dies manchmal Fehler sind, die in Point-Releases behoben wurden, und die Leute dann nicht replizieren können usw.
– Schlitten
18. Dezember 2017 um 17:37 Uhr
@doublep Ich bin mir nicht sicher, ob Sie es als gierig bezeichnen würden, aber es ist nicht erlaubt, eine einzelne CR-LF-Sequenz beim Abgleich zurückzuverfolgen und in zwei Teile zu zerlegen
\R
, weil es verboten ist, nur ein CR zu finden, wenn LF folgt. Eine andere Möglichkeit, dies auszudrücken, ist, dass es nicht zurückgehen kann. Java 8 war korrekt; Soweit ich das beurteilen kann, ist Java 9 jetzt nicht mehr konform mit tr18.– tchrist
19. Dezember 2017 um 2:32 Uhr