Frage Warum verhält sich \ R in regulären Ausdrücken zwischen Java 8 und Java 9 anders?


Der folgende Code wird in Java 8 und 9 kompiliert, 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 starte, gibt es 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

Warum?


76
2017-12-18 15:53


Ursprung


Antworten:


Das Java-Dokumentation entspricht nicht dem Unicode-Standard. Der Javadoc wittert was \R soll zusammenpassen. Es liest:

\R   Jede Unicode-Zeilenumbrüchtfolge entspricht \u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]

Diese Java-Dokumentation ist fehlerhaft. In seinem Abschnitt zu R1.6-Zeilenumbrüchen, Unicode Technical Standard # 18 zu regulären Ausdrücken sagt klar aus:

Es wird dringend empfohlen, dass ein Meta-Zeichen für reguläre Ausdrücke wie "\ R" vorhanden sein muss, um alle oben aufgeführten Zeilenendenzeichen und -sequenzen zu finden (z. B. in # 1). Dies würde etwas entsprechen, das dem folgenden Ausdruck entspricht. Dieser Ausdruck wird durch die Notwendigkeit, Backup zu vermeiden, etwas kompliziert.

 (?:\u{D A}|(?!\u{D A})[\u{A}-\u{D}\u{85}\u{2028}\u{2029}]

Mit anderen Worten, es kann nur eine Sequenz mit zwei Codepunkten CR + LF (Wagenrücklauf + Zeilenvorschub) abgleichen oder aber ein einzelner Codepunkt von diesem Satz vorausgesetzt, dass es ist nicht nur ein Wagenrücklauf allein, dem dann ein Zeilenvorschub folgt. Das ist, weil es ist nicht erlaubt zu sichern. CRLF muss atomar sein für \R um richtig zu funktionieren.

So entspricht Java 9 nicht mehr dem, was R1.6 dringend empfiehlt. Außerdem macht es jetzt etwas, was es in Java 8 NICHT tun sollte und auch nicht tat.

Sieht so aus, als wäre es an der Zeit, dass ich Sherman (lies: Xueming Shen) wieder einen Holler geben würde. Ich habe schon früher mit ihm zusammengearbeitet, bei diesen formalen Konformitätsfragen.


46
2017-12-19 02:28



Es war ein Fehler in Java 8 und es wurde behoben: JDK-8176029: "Der Linebreak-Matcher entspricht nicht dem in javadoc angegebenen Muster".

Siehe auch: Java-8 regex negativer Lookbehind mit `\ R`


63
2017-12-18 16:11