\ R이 Java 8과 Java 9의 정규식에서 다르게 작동하는 이유는 무엇입니까?


78

다음 코드는 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);
        }
    }
}

Java 8로 실행하면 다음이 반환됩니다.

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

왜?


4
Java 8 \R에서는 탐욕스러운 것처럼 보이지만 9에서는 그렇지 않습니다.
.12.18

어떤 문자열에서 얻 System.getProperty("line.separator")습니까?
Sergey Kalinichenko

2
@dasblinkenlight : 그건 중요하지 않습니다. \R바꿈 일치 자 입니다. OP에있는 것과 일치합니다.
마코토

2
이런 종류의 질문을 게시 할 때 JDK 버전 번호를 포함하는 것이 좋습니다. 때때로 이들은 포인트 릴리스에서 수정 된 버그이고 사람들이 복제 할 수 없기 때문입니다.
Sled

2
@doublep 나는 당신이 그것을 탐욕이라고 부를지 확신하지 못하지만 일치 할 때 단일 CR LF 시퀀스를 두 개로 역 추적하고 깰 수 없습니다 \R. 왜냐하면 LF 뒤에 오는 경우 CR 만 일치하는 것이 금지되기 때문입니다. 이것을 표현하는 또 다른 방법은 역 추적 할 수 없다는 것입니다. Java 8이 정확했습니다. Java 9는 이제 내가 아는 한 tr18과 일치하지 않습니다.
tchrist

답변:


48

자바 문서는 유니 코드 표준을 준수 벗어났습니다. Javadoc \R은 일치해야하는 내용을 잘못 이해합니다 . 읽습니다.

\R 모든 유니 코드 줄 바꿈 시퀀스는 다음과 같습니다. \u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]

그 Java 문서는 버그가 있습니다. 그것에서 R1.6 줄 바꿈 섹션 정규 표현식에, 유니 코드 기술 표준 # 18 분명히 말한다 :

위에 나열된 모든 줄 끝 문자 및 시퀀스 (예 : # 1)를 일치시키기 위해 "\ R"과 같은 정규식 메타 문자가있는 것이 좋습니다. 이것은 다음 표현식과 동등한 것에 해당합니다. 이 표현은 백업을 피해야하기 때문에 약간 복잡합니다.

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

즉, 단지 두 개의 코드 포인트 CR + LF (캐리지 리턴 + 바꿈) 시퀀스를 일치시킬 수 그렇지 는 것을 제공되는 세트에서 단일 코드 포인트를 하지 후 바꿈 뒤에 만 단지 캐리지 리턴 . 백업이 허용되지 않기 때문입니다 . CRLF가 \R제대로 작동하려면 원자 적이어야합니다 .

따라서 Java 9는 더 이상 R1.6이 강력하게 권장하는 사항을 따르지 않습니다. 또한 Java 8에서는하지 말아야 할 일을하고 있고하지 말아야 할 일을하고 있습니다.

Sherman (읽기 : Xueming Shen)에게 다시 외칠 때가 된 것 같습니다. 나는 이전에 공식적인 적합성의 핵심적인 문제에 대해 그와 함께 일했습니다.


2
따라서 해결 방법은 (?>\\R)또는 \\R{1}+대신 \\R또는 OP의 특정 경우 \\R{2}+대신 사용하는 것입니다 \\R\\R. 흥미롭게도, 비 소유자 가 역 추적을 비활성화해서는 안되기 때문에 일관성이없는 Java 9 하에서 원하는 결과를 제공 \\R{1}\\R{1}하거나 \\R{2}제공합니다 {n}.
Holger

어쩌면 이것은 JDK-8176983으로 고칠 수 있습니까?
Naman

@nullpointer 누구든지 이것이 Java 10에서 수정되었는지 알 수 있습니까? javadoc에 여전히 잘못된 "동등한"패턴이있는 것처럼 보이므로 적어도 구현이 아니라면 문서가 잘못되었습니다.
Patrick Parker

63

7
흥미롭게도 Java 8 동작이 더 건전 해 보입니다. "\ r \ n"을 두 개의 연속적인 줄 바꿈으로 해석 할 수는 있지만, 제가보기에는 거의 의미가 없습니다. 두 개의 줄 바꿈을 의미했다면 "\ n \ n"또는 "\ r \ n \ r \ n"등을 쓸 것 입니다. 즉, 두 개의 동일한 줄 바꿈입니다. "\ r \ n"은 실제로 하나를 의미해야합니다.
.12.18

2
말이 되는군요!. 그러나 Java 8에는 필요한 동작이 있습니다. mmmh.
Germán Bouzas

3
@ GermánBouzas : 먼저 줄 바꿈을 정규화해야한다고 생각합니다 replaceAll ("\\R", "\\n").
.12.18

9
나는 이것이 오류라고 확신합니다. \R역 추적 될 수 없어야합니다. 이에 대한 확실한 이유가 있습니다. 내가 찾을 수있는 것을 보겠습니다. CRLF를 두 개의 인스턴스 또는 \R.
tchrist
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.