[java] 정규식을 사용하여 여러 줄 문자 일치

java를 사용하여 여러 줄 텍스트를 일치 시키려고합니다. 수정 자 Pattern와 함께 클래스를 사용할 때 Pattern.MULTILINE일치시킬 수는 있지만 그렇게 할 수는 없습니다.(?m).

(?m)사용하고 사용 하는 동일한 패턴이 String.matches작동하지 않는 것 같습니다.

나는 무언가를 놓치고 있다고 확신하지만, 무엇을 모른다. 정규 표현식에별로 좋지 않습니다.

이것이 내가 시도한 것입니다

String test = "User Comments: This is \t a\ta \n test \n\n message \n";

String pattern1 = "User Comments: (\\W)*(\\S)*";
Pattern p = Pattern.compile(pattern1, Pattern.MULTILINE);
System.out.println(p.matcher(test).find());  //true

String pattern2 = "(?m)User Comments: (\\W)*(\\S)*";
System.out.println(test.matches(pattern2));  //false - why?



답변

먼저 잘못된 가정 하에서 수정자를 사용하고 있습니다.

Pattern.MULTILINE또는 (?m)앵커을 받아 자바를 지시 ^하고 $시작 부분에서 일치하고 각 줄의 끝 (그렇지 않으면 그들은 단지 전체 문자열의 시작 / 끝 부분에 일치).

Pattern.DOTALL또는 (?s)점이 개행 문자와 일치하도록 Java에 지시합니다.

둘째, 정규 표현식이 전체 문자열 matches()과 일치 할 것으로 예상 하는 방법을 사용하기 때문에 정규 표현식이 실패합니다. 일부 문자 가 일치하기 때문에 작동하지 않습니다 .(\\W)*(\\S)*

따라서 단순히로 시작하는 문자열을 찾고 있다면 User Comments:정규식을 사용하십시오.

^\s*User Comments:\s*(.*)

Pattern.DOTALL옵션 :

Pattern regex = Pattern.compile("^\\s*User Comments:\\s+(.*)", Pattern.DOTALL);
Matcher regexMatcher = regex.matcher(subjectString);
if (regexMatcher.find()) {
    ResultString = regexMatcher.group(1);
} 

ResultString 다음에 텍스트를 포함합니다 User Comments:


답변

이것은 MULTILINE 플래그와 관련이 없습니다. 당신이보고있는 것은 사이의 차이 find()matches()방법. find()일치가 발견 될 수 있다면 성공 의 아무 곳이나 대상 문자열에 있는 동안, matches()일치하는 정규 표현식 기대 전체 문자열을 .

Pattern p = Pattern.compile("xyz");

Matcher m = p.matcher("123xyzabc");
System.out.println(m.find());    // true
System.out.println(m.matches()); // false

Matcher m = p.matcher("xyz");
System.out.println(m.matches()); // true

또한, MULTILINE당신이 생각하는 것을 의미하지는 않습니다. 많은 사람들이 대상 문자열에 줄 바꿈이 포함되어있는 경우, 즉 여러 개의 논리적 줄이 포함 된 경우 해당 플래그를 사용해야한다는 결론에 도달하는 것 같습니다. 그 효과에 여기에 SO에 대한 몇 가지 답변을 본 적이 있지만 사실, 플래그가하는 모든 앵커의 동작을 변경하고, ^그리고$ .

일반적으로 ^대상 문자열의 맨 처음과 $일치하고 맨 끝 과 일치합니다 (또는 끝에서 줄 바꿈 전에)하지만 지금은 따로 둡니다. 문자열은 줄 바꿈이 포함 된 경우 그러나, 당신이 선택할 수 ^$ 여러 줄 플래그를 설정하여, 시작 부분에서 일치하고 논리 행이 아니라 시작에 불과하고 전체 문자열의 끝의 끝.

그래서 잊어 MULTILINE 의미 와 그냥 기억 하지 :의 행동 변화 ^$앵커. DOTALL모드는 원래 “단일 라인”이라고하며 (그리고 여전히 Perl 및 .NET을 포함한 일부 맛이 있습니다) 항상 유사한 혼란을 일으켰습니다. 이 경우 Java 개발자가 더 설명적인 이름으로 사용되었지만 “다중 라인”모드에 대한 합리적인 대안은 없었습니다.

이 모든 광기가 시작된 Perl에서, 그들은 실수를 인정하고 Perl 6 정규 표현식에서 “멀티 라인”과 “단일 라인”모드를 모두 제거했습니다. 다른 20 년 안에 아마도 세계의 나머지 지역이 뒤 따랐을 것입니다.


답변

str.matches(regex) Pattern.matches(regex, str)전체 입력 시퀀스를 패턴과 일치 시키려고 시도하는 것처럼 동작 하고

true전체 입력 시퀀스가이 매처의 패턴과 일치 하는 경우에만

반면 패턴과 일치하는 입력 시퀀스의 다음 하위 시퀀스 matcher.find() 를 찾으려고 시도 하지만

true입력 시퀀스 의 하위 순서가이 매처의 패턴과 일치 하는 경우에만

따라서 문제는 정규식에 있습니다. 다음을 시도하십시오.

String test = "User Comments: This is \t a\ta \ntest\n\n message \n";

String pattern1 = "User Comments: [\\s\\S]*^test$[\\s\\S]*";
Pattern p = Pattern.compile(pattern1, Pattern.MULTILINE);
System.out.println(p.matcher(test).find());  //true

String pattern2 = "(?m)User Comments: [\\s\\S]*^test$[\\s\\S]*";
System.out.println(test.matches(pattern2));  //true

즉, (\\W)*(\\S)*첫 번째 정규 표현식 의 부분 *은 0 이상 발생 을 의미 하는 빈 문자열과 일치하며 실제 일치하는 문자열은 User Comments:예상대로 전체 문자열이 아닙니다. 두 번째 문자열은 전체 문자열을 일치 시키려고하는데 실패하지만 \\W비 단어 문자와 일치 할 수 없습니다.[^a-zA-Z0-9_] 번째 문자는 첫 번째 문자는 T단어 문자입니다.


답변

여러 줄 플래그는 와일드 카드로 충분할 목적으로 전체 문자열이 아닌 패턴을 각 줄에 일치 시키도록 정규 표현식에 지시합니다.


답변