1. ホーム
  2. java

Java 8 と Java 9 で正規表現における \R の動作が異なるのはなぜですか?

2023-08-15 06:58:47

質問

次のコードは、Java 8 と 9 の両方でコンパイルされますが、動作は異なります。

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);
        }
    }
}

Java8で実行すると、返ってきます。

Chunk : 
En un lugar
de la Mancha
de cuyo nombre
no quiero acordarme

しかし、Java 9で実行すると、出力が異なっています。

Chunk : 
En un lugar
Chunk : de la Mancha
de cuyo nombre
Chunk : no quiero acordarme

どうして?

どのように解決するのか?

この Java ドキュメント はUnicode標準に適合していません。Javadocは何を間違えているか \R がマッチするはずのものを間違えています。それは読むことができます。

\R Unicode の改行コードはすべて \u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]

そのJavaのドキュメントはバグだらけです。その中で セクションで、R1.6 Line Break, Unicode Technical Standard #18 on Regular Expressions を参照してください。 には、はっきりとこう書かれています。

上記(例えば#1)のすべての行末文字やシーケンスにマッチするように、" \R" のような正規表現のメタ文字を設けることを強くお勧めします。これは次のような表現に相当します。 この式は、バックアップを避ける必要があるため、少し複雑になっています。

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

つまり、2つのコードポイント CR+LF (carriage return + linefeed) のシーケンスにのみマッチします。 または である場合、そのセットからの単一のコードポイント。 ではない がキャリッジリターンだけで、その後にラインフィードが続く場合です。それは、それが をバックアップすることができないからです。 . にはCRLFは必須です。 \R が正しく機能するためには

つまり、Java 9はもはやR1.6が強く推奨するものに準拠していないのです。さらに、Java 9 は、Java 8 では行わないことになっていた、そして行わなかったことを現在行っています。

どうやら、Sherman (Xueming Shenと読みます) に再び電話をする時が来たようです。 私は以前、形式的な適合性に関する細かい事柄について、彼と一緒に仕事をしたことがあります。