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


174

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?

답변:


298

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

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:


"User Comments :"로 시작하는 문자열과 일치하는 패턴을 찾으려고합니다. 이 "사용자 의견 :"후 포함 할 수 있으므로 사용자가 텍스트 영역에 입력 뭔가이며, 무엇이든 - 심지어 새로운 라인. 정규식에서 많은 것을 배울 필요가있는 것 같습니다 ...
Nivas

2
이것은 작동합니다 (감사합니다!) 패턴을 시도했습니다 (?s)User Comments:\s*(.*). @ Amarghosh의 답변에서 패턴을 얻었습니다 User Comments: [\\s\\S]*. 이 중 더 좋 거나 권장되는 방법이 있습니까? 아니면 두 가지 다른 방법으로 동일한 작업을 수행합니까?
니 바스

3
둘 다 같은 의미입니다. [\s\S]좀 더 명확합니다 ( "공백 또는 비 공백 문자와 일치"), .읽기는 쉽지만 개행이 포함되는지 여부를 확인하려면 (?s)또는 DOTALL수정자를 찾아야합니다. 내가 선호하는 것 .으로 Pattern.DOTALL이 읽고보다 기억하기 쉽다 (플래그가 설정되어 (?s)내 생각에 당신은 당신이 가장 편안하게 느끼는 것을 사용해야합니다..
팀 Pietzcker에게

.*와 함께 DOTALL더 읽기 쉽습니다. 다른 하나를 사용하여 문제가 플래그가 아닌 str.matches와 matcher.find의 차이점에 있음을 보여주었습니다. +1
Amarghosh

내가 선호 .*Pattern.DOTALL내가 사용하기 때문에 (? S),하지만 함께 가야 할 것이다 String.matches.
Nivas

42

이것은 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 년 안에 아마도 세계의 나머지 지역이 뒤 따랐을 것입니다.


5
하드가 의미하는 메소드 이름 "#matches"를 사용 믿는 이궁 "모두 일치"합니다
rogerdpack

@ alan-moore 죄송합니다. [수면이 더 필요합니다.]]
-Raymond Naseef

22

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단어 문자입니다.


"User Comments"로 시작하는 문자열을 일치 시키려고하며 문자열에도 줄 바꿈이 포함될 수 있습니다. 그래서 나는 패턴을 사용 User Comments: [\\s\\S]*했고 이것이 효과가있었습니다. (감사합니다!) @ 팀 I의 대답에서이 패턴을 가지고 User Comments:(.*)이 확인 이제도하는이, 추천 또는 더 나은 방법은이 사이에, 또는 같은 일을 이러한 두 가지 방법이있다?
니 바스

@Nivas 나는 현명한 성능 차이가 없을 것이라고 생각합니다. 그러나 플래그 (.*)와 함께 DOTALL보다 분명하고 읽기 ([\\s\\S]*)
쉽다고

이것은 최고의 답변입니다 .... MultiLine 기능에 대한 Java 코드 및 패턴 문자열 옵션에 대한 액세스를 제공합니다.
GoldBishop

0

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.