1. 개요

이 사용방법(예제)에서는 Java Regex API에 대해 설명하고 Java 프로그래밍 언어에서 정규식을 사용하는 방법에 대해 설명합니다.

정규 표현식의 세계에는 grep, Perl, Python, PHP, awk 등과 같이 선택할 수 있는 다양한 종류가 있습니다.

이는 한 프로그래밍 언어에서 작동하는 정규식이 다른 프로그래밍 언어에서는 작동하지 않을 수 있음을 의미합니다. Java의 정규식 구문은 Perl의 구문과 가장 유사합니다.

2. 설정

Java에서 정규식을 사용하기 위해 특별한 설정이 필요하지 않습니다. JDK에는 정규식 작업 전용인 특수 패키지인 java.util.regex 가 포함되어 있습니다. 코드로 가져오기만 하면 됩니다.

또한 java.lang.String 클래스에는 코드에서 일반적으로 사용하는 정규식 지원이 내장되어 있습니다.

3. 자바 정규식 패키지

java.util.regex 패키지는 Pattern, MatcherPatternSyntaxException 의 세 가지 클래스로 구성됩니다 .

  • 패턴 개체는 컴파일된 정규식입니다. Pattern 클래스 는 공용 생성자를 제공하지 않습니다. 패턴을 만들려면 먼저 공용 정적 컴파일 메서드 중 하나를 호출해야 합니다. 그런 다음 패턴 개체 를 반환 합니다. 이러한 메서드는 첫 번째 인수로 정규식을 허용합니다.
  • Matcher 개체는 패턴을 해석하고 입력 String 에 대해 일치 작업을 수행합니다 . 또한 공용 생성자를 정의하지 않습니다. Pattern 개체에서 matcher 메서드를 호출하여 Matcher 개체를 얻습니다 .
  • PatternSyntaxException 개체는 정규식 패턴의 구문 오류를 나타내는 확인되지 않은 예외입니다.

이러한 클래스를 자세히 살펴보겠습니다. 그러나 먼저 Java에서 정규식을 구성하는 방법을 이해해야 합니다.

다른 환경의 정규식에 이미 익숙하다면 특정 차이점을 발견할 수 있지만 그 정도는 미미합니다.

4. 간단한 예

정규식의 가장 간단한 사용 사례부터 시작하겠습니다. 앞에서 언급했듯이 문자열에 정규식을 적용하면 0번 이상 일치할 수 있습니다.

java.util.regex API가 지원하는 패턴 일치의 가장 기본적인 형태는 문자열 리터럴 의 일치입니다 . 예를 들어, 정규 표현식이 foo 이고 입력 문자열foo 이면 문자열 이 동일 하기 때문에 일치가 성공 합니다.

@Test
public void givenText_whenSimpleRegexMatches_thenCorrect() {
    Pattern pattern = Pattern.compile("foo");
    Matcher matcher = pattern.matcher("foo");
 
    assertTrue(matcher.find());
}

먼저 정적 컴파일 메서드 를 호출하고 사용하려는 패턴을 전달 하여 Pattern 개체를 만듭니다.

그런 다음 Pattern 개체의 matcher 메서드를 호출하고 일치를 확인하려는 텍스트를 전달 하는 Matcher 개체를 만듭니다.

마지막으로 Matcher 개체에서 find 메서드를 호출합니다.

find 메서드 는 입력 텍스트를 통해 계속 진행하고 모든 일치 항목에 대해 true를 반환하므로 일치 항목 수를 찾는 데에도 사용할 수 있습니다.

@Test
public void givenText_whenSimpleRegexMatchesTwice_thenCorrect() {
    Pattern pattern = Pattern.compile("foo");
    Matcher matcher = pattern.matcher("foofoo");
    int matches = 0;
    while (matcher.find()) {
        matches++;
    }
 
    assertEquals(matches, 2);
}

더 많은 테스트를 실행할 것이므로 runTest 라는 메서드에서 일치 항목 수를 찾는 논리를 추상화할 수 있습니다 .

public static int runTest(String regex, String text) {
    Pattern pattern = Pattern.compile(regex);
    Matcher matcher = pattern.matcher(text);
    int matches = 0;
    while (matcher.find()) {
        matches++;
    }
    return matches;
}

일치하는 항목이 없으면 테스트가 실패해야 합니다. 그렇지 않으면 통과해야 합니다.

5. 메타 캐릭터

메타 문자는 패턴 일치 방식에 영향을 미칩니다. 어떤 방식으로 그들은 검색 패턴에 논리를 추가합니다. Java API는 여러 메타 문자를 지원하며 가장 간단한 것은 모든 문자와 일치하는 점 "."입니다 .

@Test
public void givenText_whenMatchesWithDotMetach_thenCorrect() {
    int matches = runTest(".", "foo");
    
    assertTrue(matches > 0);
}

정규식 foo 가 텍스트 foofoofoo를 두 번 일치 시킨 이전 예를 살펴보겠습니다 . 정규식에서 점 메타 문자를 사용하면 두 번째 경우에 두 개의 일치 항목을 얻지 못합니다.

@Test
public void givenRepeatedText_whenMatchesOnceWithDotMetach_thenCorrect() {
    int matches= runTest("foo.", "foofoo");
 
    assertEquals(matches, 1);
}

정규식에서 foo 뒤에 있는 점에 주목하십시오 . 매처는 foo 가 앞에 오는 모든 텍스트와 일치합니다 . 마지막 점 부분은 이후의 모든 문자를 의미하기 때문입니다. 따라서 첫 번째 foo 를 찾은 후 나머지는 랜덤의 문자로 표시됩니다. 그렇기 때문에 단 한 번의 경기만 있는 것입니다.

API는 <([{\^-=$!|]})?*+.>와 같은 몇 가지 다른 메타 문자를 지원하며 이 문서에서 자세히 살펴보겠습니다.

6. 캐릭터 클래스

공식 Pattern 클래스 사양을 탐색하면 지원되는 정규식 구성의 요약을 찾을 수 있습니다. 캐릭터 클래스 아래에는 약 6개의 구성이 있습니다.

6.1. 또는 클래스

이것을 [abc] 로 구성합니다 . 이는 세트의 모든 요소와 일치합니다.

@Test
public void givenORSet_whenMatchesAny_thenCorrect() {
    int matches = runTest("[abc]", "b");
 
    assertEquals(matches, 1);
}

텍스트에 모두 표시되면 순서에 관계없이 각 요소를 개별적으로 일치시킵니다.

@Test
public void givenORSet_whenMatchesAnyAndAll_thenCorrect() {
    int matches = runTest("[abc]", "cab");
 
    assertEquals(matches, 3);
}

String 의 일부로 대체될 수도 있습니다 . 다음 예에서 세트의 각 요소와 첫 번째 문자를 번갈아 가며 다른 단어를 만들면 모두 일치합니다.

@Test
public void givenORSet_whenMatchesAllCombinations_thenCorrect() {
    int matches = runTest("[bcr]at", "bat cat rat");
 
    assertEquals(matches, 3);
}

6.2. NOR 클래스

위의 집합은 캐럿을 첫 번째 요소로 추가하여 무효화됩니다.

@Test
public void givenNORSet_whenMatchesNon_thenCorrect() {
    int matches = runTest("[^abc]", "g");
 
    assertTrue(matches > 0);
}

다른 경우가 있습니다.

@Test
public void givenNORSet_whenMatchesAllExceptElements_thenCorrect() {
    int matches = runTest("[^bcr]at", "sat mat eat");
 
    assertTrue(matches > 0);
}

6.3. 범위 클래스

하이픈(-)을 사용하여 일치하는 텍스트가 속해야 하는 범위를 지정하는 클래스를 정의할 수 있습니다. 마찬가지로 범위를 부정할 수도 있습니다.

일치하는 대문자:

@Test
public void givenUpperCaseRange_whenMatchesUpperCase_
  thenCorrect() {
    int matches = runTest(
      "[A-Z]", "Two Uppercase alphabets 34 overall");
 
    assertEquals(matches, 2);
}

일치하는 소문자:

@Test
public void givenLowerCaseRange_whenMatchesLowerCase_
  thenCorrect() {
    int matches = runTest(
      "[a-z]", "Two Uppercase alphabets 34 overall");
 
    assertEquals(matches, 26);
}

대문자와 소문자 모두 일치:

@Test
public void givenBothLowerAndUpperCaseRange_
  whenMatchesAllLetters_thenCorrect() {
    int matches = runTest(
      "[a-zA-Z]", "Two Uppercase alphabets 34 overall");
 
    assertEquals(matches, 28);
}

주어진 숫자 범위 일치:

@Test
public void givenNumberRange_whenMatchesAccurately_
  thenCorrect() {
    int matches = runTest(
      "[1-5]", "Two Uppercase alphabets 34 overall");
 
    assertEquals(matches, 2);
}

다른 숫자 범위 일치:

@Test
public void givenNumberRange_whenMatchesAccurately_
  thenCorrect2(){
    int matches = runTest(
      "3[0-5]", "Two Uppercase alphabets 34 overall");
  
    assertEquals(matches, 1);
}

6.4. 유니온 클래스

통합 문자 클래스는 두 개 이상의 문자 클래스를 결합한 결과입니다.

@Test
public void givenTwoSets_whenMatchesUnion_thenCorrect() {
    int matches = runTest("[1-3[7-9]]", "123456789");
 
    assertEquals(matches, 6);
}

위의 테스트는 유니온 세트가 4, 5, 6을 건너뛰기 때문에 9개의 정수 중 6개만 일치시킵니다.

6.5. 교차 클래스

유니온 클래스와 유사하게 이 클래스는 둘 이상의 집합 사이에서 공통 요소를 선택하여 생성됩니다. 교차를 적용하려면 && 를 사용합니다 .

@Test
public void givenTwoSets_whenMatchesIntersection_thenCorrect() {
    int matches = runTest("[1-6&&[3-9]]", "123456789");
 
    assertEquals(matches, 4);
}

두 세트의 교집합에는 4개의 요소만 있기 때문에 4개의 일치 항목을 얻습니다.

6.6. 빼기 클래스

빼기를 사용하여 하나 이상의 문자 클래스를 부정할 수 있습니다. 예를 들어 홀수 십진수 집합을 일치시킬 수 있습니다.

@Test
public void givenSetWithSubtraction_whenMatchesAccurately_thenCorrect() {
    int matches = runTest("[0-9&&[^2468]]", "123456789");
 
    assertEquals(matches, 5);
}

1, 3, 5, 7, 9일치합니다.

7. 미리 정의된 문자 클래스

Java regex API는 미리 정의된 문자 클래스도 허용합니다. 위의 문자 클래스 중 일부는 코드를 덜 직관적으로 만들지만 더 짧은 형식으로 표현할 수 있습니다. 이 정규식의 Java 버전의 특별한 측면 중 하나는 이스케이프 문자입니다.

앞으로 살펴보겠지만 대부분의 문자는 백슬래시로 시작하며 이는 Java에서 특별한 의미를 갖습니다. Pattern 클래스 로 컴파일 하려면 선행 백슬래시를 이스케이프 처리해야 합니다. 즉, \d\\d 가 됩니다 .

[0-9] 에 해당하는 일치하는 숫자 :

@Test
public void givenDigits_whenMatches_thenCorrect() {
    int matches = runTest("\\d", "123");
 
    assertEquals(matches, 3);
}

숫자가 아닌 일치, [^0-9] 와 동일 :

@Test
public void givenNonDigits_whenMatches_thenCorrect() {
    int mathces = runTest("\\D", "a6c");
 
    assertEquals(matches, 2);
}

일치하는 공백:

@Test
public void givenWhiteSpace_whenMatches_thenCorrect() {
    int matches = runTest("\\s", "a c");
 
    assertEquals(matches, 1);
}

공백이 아닌 일치:

@Test
public void givenNonWhiteSpace_whenMatches_thenCorrect() {
    int matches = runTest("\\S", "a c");
 
    assertEquals(matches, 2);
}

[a-zA-Z_0-9] 에 해당하는 단어 문자 일치 :

@Test
public void givenWordCharacter_whenMatches_thenCorrect() {
    int matches = runTest("\\w", "hi!");
 
    assertEquals(matches, 2);
}

비단어 문자 일치:

@Test
public void givenNonWordCharacter_whenMatches_thenCorrect() {
    int matches = runTest("\\W", "hi!");
 
    assertEquals(matches, 1);
}

8. 수량사

Java regex API를 사용하면 수량자를 사용할 수도 있습니다. 이를 통해 일치시킬 항목 수를 지정하여 일치 동작을 추가로 조정할 수 있습니다.

텍스트를 0번 또는 1번 일치시키려면 ? 한정사:

@Test
public void givenZeroOrOneQuantifier_whenMatches_thenCorrect() {
    int matches = runTest("\\a?", "hi");
 
    assertEquals(matches, 3);
}

또는 Java regex API에서도 지원하는 중괄호 구문을 사용할 수 있습니다.

@Test
public void givenZeroOrOneQuantifier_whenMatches_thenCorrect2() {
    int matches = runTest("\\a{0,1}", "hi");
 
    assertEquals(matches, 3);
}

이 예에서는 길이가 0인 일치 개념을 소개합니다. 한정 기호의 일치 임계값이 0이면 모든 입력 끝에 있는 빈 문자열 을 포함하여 항상 텍스트의 모든 항목과 일치합니다. 즉, 입력이 비어 있어도 길이가 0인 일치 항목이 하나 반환됩니다.

이것은 길이가 2인 S 문자열 이 있음에도 불구하고 위의 예에서 세 개의 일치 항목을 얻는 이유를 설명합니다 . 세 번째 일치 항목은 길이가 0인 빈 String 입니다.

텍스트를 0번 또는 무제한으로 일치시키려면 ?와 유사한 * 수량자를 사용합니다.

@Test
public void givenZeroOrManyQuantifier_whenMatches_thenCorrect() {
     int matches = runTest("\\a*", "hi");
 
     assertEquals(matches, 3);
}

지원되는 대안:

@Test
public void givenZeroOrManyQuantifier_whenMatches_thenCorrect2() {
    int matches = runTest("\\a{0,}", "hi");
 
    assertEquals(matches, 3);
}

차이가 있는 수량어는 +이며 일치하는 임계값은 1입니다. 필수 문자열 이 전혀 발생하지 않으면 길이가 0인 문자열 도 일치하지 않습니다 .

@Test
public void givenOneOrManyQuantifier_whenMatches_thenCorrect() {
    int matches = runTest("\\a+", "hi");
 
    assertFalse(matches);
}

지원되는 대안:

@Test
public void givenOneOrManyQuantifier_whenMatches_thenCorrect2() {
    int matches = runTest("\\a{1,}", "hi");
 
    assertFalse(matches);
}

Perl 및 기타 언어에서와 같이 중괄호 구문을 사용하여 주어진 텍스트를 여러 번 일치시킬 수 있습니다.

@Test
public void givenBraceQuantifier_whenMatches_thenCorrect() {
    int matches = runTest("a{3}", "aaaaaa");
 
    assertEquals(matches, 2);
}

위의 예에서는 a 가 연속으로 세 번 나타나는 경우에만 일치가 발생하므로 두 개의 일치를 얻습니다 . 그러나 다음 테스트에서는 텍스트가 연속으로 두 번만 나타나기 때문에 일치 항목을 얻지 못할 것입니다.

@Test
public void givenBraceQuantifier_whenFailsToMatch_thenCorrect() {
    int matches = runTest("a{3}", "aa");
 
    assertFalse(matches > 0);
}

중괄호에 범위를 사용하면 범위의 높은 쪽 끝에서 일치하는 탐욕적인 일치가 이루어집니다.

@Test
public void givenBraceQuantifierWithRange_whenMatches_thenCorrect() {
    int matches = runTest("a{2,3}", "aaaa");
 
    assertEquals(matches, 1);
}

여기서 우리는 최소 2개의 발생을 지정했지만 3개를 초과하지 않으므로 일치자가 단일 aaa 및 단독 a를 보는 단일 일치를 얻습니다. 이는 일치할 수 없습니다.

그러나 API를 사용하면 일치자가 범위의 하단에서 시작하여 aaaa 와 같은 두 항목을 일치시킬 수 있도록 게으르거나 꺼리는 방식을 지정할 수 있습니다 .

@Test
public void givenBraceQuantifierWithRange_whenMatchesLazily_thenCorrect() {
    int matches = runTest("a{2,3}?", "aaaa");
 
    assertEquals(matches, 2);
}

9. 캡처 그룹

API를 사용하면 그룹 캡처를 통해 여러 문자를 단일 단위로 처리할 수도 있습니다 . 캡처 그룹에 번호를 첨부하고 이 번호를 사용하여 다시 참조할 수 있습니다.

이 섹션에서는 Java regex API에서 그룹 캡처를 사용하는 방법에 대한 몇 가지 예를 살펴보겠습니다.

입력 텍스트에 서로 옆에 두 개의 숫자가 포함된 경우에만 일치하는 캡처링 그룹을 사용해 보겠습니다.

@Test
public void givenCapturingGroup_whenMatches_thenCorrect() {
    int matches = runTest("(\\d\\d)", "12");
 
    assertEquals(matches, 1);
}

위의 일치 항목에 첨부된 숫자는 1 이며 역참조를 사용하여 텍스트의 일치 부분의 다른 항목과 일치시키길 원한다고 일치자에게 알립니다. 이렇게 하면 입력에 대해 두 개의 개별 일치 항목을 갖는 대신 다음과 같이 됩니다.

@Test
public void givenCapturingGroup_whenMatches_thenCorrect2() {
    int matches = runTest("(\\d\\d)", "1212");
 
    assertEquals(matches, 2);
}

하나의 일치 항목을 가질 수 있지만 역 참조를 사용하여 입력의 전체 길이에 걸쳐 동일한 정규식 일치 항목을 전파합니다.

@Test
public void givenCapturingGroup_whenMatchesWithBackReference_
  thenCorrect() {
    int matches = runTest("(\\d\\d)\\1", "1212");
 
    assertEquals(matches, 1);
}

동일한 결과를 얻으려면 역참조 없이 정규식을 반복해야 합니다.

@Test
public void givenCapturingGroup_whenMatches_thenCorrect3() {
    int matches = runTest("(\\d\\d)(\\d\\d)", "1212");
 
    assertEquals(matches, 1);
}

마찬가지로 다른 반복 횟수의 경우 역참조를 통해 일치자가 입력을 단일 일치로 볼 수 있습니다.

@Test
public void givenCapturingGroup_whenMatchesWithBackReference_
  thenCorrect2() {
    int matches = runTest("(\\d\\d)\\1\\1\\1", "12121212");
 
    assertEquals(matches, 1);
}

그러나 마지막 숫자라도 변경하면 일치가 실패합니다.

@Test
public void givenCapturingGroupAndWrongInput_
  whenMatchFailsWithBackReference_thenCorrect() {
    int matches = runTest("(\\d\\d)\\1", "1213");
 
    assertFalse(matches > 0);
}

Java 구문에서 중요한 이스케이프 백슬래시를 잊지 않는 것이 중요합니다.

10. 경계 매처

Java regex API는 경계 일치도 지원합니다. 입력 텍스트에서 일치가 발생해야 하는 정확한 위치에 관심이 있는 경우 이것이 우리가 찾고 있는 것입니다. 앞의 예에서 우리가 관심을 두는 것은 일치하는 항목이 있는지 여부였습니다.

텍스트 시작 부분에서 필수 정규식이 true인 경우에만 일치시키려면 캐럿 ^를 사용합니다.

이 테스트는 통과할 것입니다. 텍스트 를 처음에 찾을 수 있기 때문입니다.

@Test
public void givenText_whenMatchesAtBeginning_thenCorrect() {
    int matches = runTest("^dog", "dogs are friendly");
 
    assertTrue(matches > 0);
}

다음 테스트는 실패합니다.

@Test
public void givenTextAndWrongInput_whenMatchFailsAtBeginning_
  thenCorrect() {
    int matches = runTest("^dog", "are dogs are friendly?");
 
    assertFalse(matches > 0);
}

텍스트 끝에서 필수 정규식이 true인 경우에만 일치시키려면 달러 문자 $를 사용합니다. 다음과 같은 경우 일치 항목을 찾습니다.

@Test
public void givenText_whenMatchesAtEnd_thenCorrect() {
    int matches = runTest("dog$", "Man's best friend is a dog");
 
    assertTrue(matches > 0);
}

여기서는 일치하는 항목을 찾을 수 없습니다.

@Test
public void givenTextAndWrongInput_whenMatchFailsAtEnd_thenCorrect() {
    int matches = runTest("dog$", "is a dog man's best friend?");
 
    assertFalse(matches > 0);
}

필수 텍스트가 단어 경계에서 발견되는 경우에만 일치를 원하는 경우 정규식의 시작과 끝에 \\b 정규식을 사용합니다.

공백은 단어 경계입니다.

@Test
public void givenText_whenMatchesAtWordBoundary_thenCorrect() {
    int matches = runTest("\\bdog\\b", "a dog is friendly");
 
    assertTrue(matches > 0);
}

줄 시작 부분의 빈 문자열도 단어 경계입니다.

@Test
public void givenText_whenMatchesAtWordBoundary_thenCorrect2() {
    int matches = runTest("\\bdog\\b", "dog is man's best friend");
 
    assertTrue(matches > 0);
}

이러한 테스트는 String 의 시작 과 한 텍스트와 다른 텍스트 사이의 공백이 단어 경계를 표시하기 때문에 통과합니다. 그러나 다음 테스트는 그 반대를 보여줍니다.

@Test
public void givenWrongText_whenMatchFailsAtWordBoundary_thenCorrect() {
    int matches = runTest("\\bdog\\b", "snoop dogg is a rapper");
 
    assertFalse(matches > 0);
}

행에 나타나는 두 단어 문자는 단어 경계를 표시하지 않지만 비단어 경계를 찾기 위해 정규식의 끝을 변경하여 통과하도록 만들 수 있습니다.

@Test
public void givenText_whenMatchesAtWordAndNonBoundary_thenCorrect() {
    int matches = runTest("\\bdog\\B", "snoop dogg is a rapper");
    assertTrue(matches > 0);
}

11. 패턴 클래스 메서드

이전 에는 기본 방식으로 Pattern 개체 만 만들었습니다 . 그러나 이 클래스에는 regex 인수와 함께 플래그 세트를 허용하는 컴파일 메소드의 또 다른 변형이 있습니다. 이는 패턴을 일치시키는 방식에 영향을 미칩니다.

이러한 플래그는 단순히 추상화된 정수 값입니다. 플래그를 세 번째 인수로 사용할 수 있도록 테스트 클래스에서 runTest 메서드를 오버로드합니다 .

public static int runTest(String regex, String text, int flags) {
    pattern = Pattern.compile(regex, flags);
    matcher = pattern.matcher(text);
    int matches = 0;
    while (matcher.find()){
        matches++;
    }
    return matches;
}

이 섹션에서는 지원되는 다양한 플래그와 이를 사용하는 방법을 살펴보겠습니다.

패턴.CANON_EQ

이 플래그는 정규 동등성을 사용합니다. 지정된 경우 두 문자는 전체 표준 분해가 일치하는 경우에만 일치하는 것으로 간주됩니다.

악센트가 있는 유니코드 문자 é 를 고려하십시오 . 복합 코드 포인트는 u00E9 입니다. 그러나 유니코드에는 구성 문자 e , u0065 및 양음 부호 u0301 에 대한 별도의 코드 포인트도 있습니다 . 이 경우 복합 문자 u00E9두 문자 시퀀스 u 와 구별할 수 없습니다.00650301 .

기본적으로 일치는 정규 동등성을 고려하지 않습니다.

@Test
public void givenRegexWithoutCanonEq_whenMatchFailsOnEquivalentUnicode_thenCorrect() {
    int matches = runTest("\u00E9", "\u0065\u0301");
 
    assertFalse(matches > 0);
}

그러나 플래그를 추가하면 테스트가 통과됩니다.

@Test
public void givenRegexWithCanonEq_whenMatchesOnEquivalentUnicode_thenCorrect() {
    int matches = runTest("\u00E9", "\u0065\u0301", Pattern.CANON_EQ);
 
    assertTrue(matches > 0);
}

패턴.CASE_INSENSITIVE

이 플래그는 대소문자에 관계없이 일치를 가능하게 합니다. 기본적으로 일치는 대소문자를 고려합니다.

@Test
public void givenRegexWithDefaultMatcher_whenMatchFailsOnDifferentCases_thenCorrect() {
    int matches = runTest("dog", "This is a Dog");
 
    assertFalse(matches > 0);
}

따라서 이 플래그를 사용하여 기본 동작을 변경할 수 있습니다.

@Test
public void givenRegexWithCaseInsensitiveMatcher
  _whenMatchesOnDifferentCases_thenCorrect() {
    int matches = runTest(
      "dog", "This is a Dog", Pattern.CASE_INSENSITIVE);
 
    assertTrue(matches > 0);
}

동일한 결과를 얻기 위해 동등한 내장 플래그 표현식을 사용할 수도 있습니다.

@Test
public void givenRegexWithEmbeddedCaseInsensitiveMatcher
  _whenMatchesOnDifferentCases_thenCorrect() {
    int matches = runTest("(?i)dog", "This is a Dog");
 
    assertTrue(matches > 0);
}

패턴.댓글

Java API를 사용하면 정규식에 #을 사용하여 어노테이션을 포함할 수 있습니다. 이는 다른 프로그래머에게 즉시 명확하지 않을 수 있는 복잡한 정규식을 문서화하는 데 도움이 될 수 있습니다.

어노테이션 플래그는 일치자가 정규식의 공백이나 어노테이션을 무시하고 패턴만 고려하도록 합니다. 기본 일치 모드에서 다음 테스트는 실패합니다.

@Test
public void givenRegexWithComments_whenMatchFailsWithoutFlag_thenCorrect() {
    int matches = runTest(
      "dog$  #check for word dog at end of text", "This is a dog");
 
    assertFalse(matches > 0);
}

이는 매처가 공백과 # 문자를 포함하여 입력 텍스트에서 전체 정규식을 찾기 때문입니다. 그러나 플래그를 사용하면 추가 공백을 무시하고 #로 시작하는 모든 텍스트는 각 줄에 대해 무시할 어노테이션으로 표시됩니다.

@Test
public void givenRegexWithComments_whenMatchesWithFlag_thenCorrect() {
    int matches = runTest(
      "dog$  #check end of text","This is a dog", Pattern.COMMENTS);
 
    assertTrue(matches > 0);
}

이에 대한 대체 내장 플래그 표현식도 있습니다.

@Test
public void givenRegexWithComments_whenMatchesWithEmbeddedFlag_thenCorrect() {
    int matches = runTest(
      "(?x)dog$  #check end of text", "This is a dog");
 
    assertTrue(matches > 0);
}

패턴.도탈

기본적으로 점 "."을 사용할 때 정규식의 식에서 새 줄 문자를 만날 때까지 입력 문자열 의 모든 문자를 일치시킵니다.

이 플래그를 사용하면 일치 항목에 줄 종결자도 포함됩니다. 다음 예를 통해 이를 더 잘 이해할 수 있습니다. 이러한 예는 약간 다를 것입니다. 일치하는 String 에 대해 주장하기를 원하므로 이전 일치 항목을 반환하는 matcher그룹 메서드를 사용 합니다.

먼저 기본 동작을 살펴보겠습니다.

@Test
public void givenRegexWithLineTerminator_whenMatchFails_thenCorrect() {
    Pattern pattern = Pattern.compile("(.*)");
    Matcher matcher = pattern.matcher(
      "this is a text" + System.getProperty("line.separator") 
        + " continued on another line");
    matcher.find();
 
    assertEquals("this is a text", matcher.group(1));
}

보시다시피 줄 종결자 앞의 입력의 첫 번째 부분만 일치합니다.

이제 dotall 모드에서 줄 종결자를 포함한 전체 텍스트가 일치합니다.

@Test
public void givenRegexWithLineTerminator_whenMatchesWithDotall_thenCorrect() {
    Pattern pattern = Pattern.compile("(.*)", Pattern.DOTALL);
    Matcher matcher = pattern.matcher(
      "this is a text" + System.getProperty("line.separator") 
        + " continued on another line");
    matcher.find();
    assertEquals(
      "this is a text" + System.getProperty("line.separator") 
        + " continued on another line", matcher.group(1));
}

포함된 플래그 표현식을 사용하여 dotall 모드를 활성화할 수도 있습니다.

@Test
public void givenRegexWithLineTerminator_whenMatchesWithEmbeddedDotall
  _thenCorrect() {
    
    Pattern pattern = Pattern.compile("(?s)(.*)");
    Matcher matcher = pattern.matcher(
      "this is a text" + System.getProperty("line.separator") 
        + " continued on another line");
    matcher.find();
 
    assertEquals(
      "this is a text" + System.getProperty("line.separator") 
        + " continued on another line", matcher.group(1));
}

패턴.리터럴

이 모드에서는 매처가 메타 문자, 이스케이프 문자 또는 정규식 구문에 특별한 의미를 부여하지 않습니다. 이 플래그가 없으면 매처는 모든 입력 문자열 에 대해 다음 정규식을 일치시킵니다 .

@Test
public void givenRegex_whenMatchesWithoutLiteralFlag_thenCorrect() {
    int matches = runTest("(.*)", "text");
 
    assertTrue(matches > 0);
}

이것은 모든 예제에서 본 기본 동작입니다. 그러나 이 플래그를 사용하면 일치하는 항목을 찾지 못할 것입니다. 일치자가 해석하는 대신 (.*) 를 찾을 것이기 때문입니다.

@Test
public void givenRegex_whenMatchFailsWithLiteralFlag_thenCorrect() {
    int matches = runTest("(.*)", "text", Pattern.LITERAL);
 
    assertFalse(matches > 0);
}

이제 필요한 문자열을 추가하면 테스트가 통과합니다.

@Test
public void givenRegex_whenMatchesWithLiteralFlag_thenCorrect() {
    int matches = runTest("(.*)", "text(.*)", Pattern.LITERAL);
 
    assertTrue(matches > 0);
}

리터럴 구문 분석을 활성화하기 위한 포함된 플래그 문자가 없습니다.

패턴.멀티라인

기본적으로 ^$ 메타 문자는 각각 전체 입력 String 의 처음과 끝에서 절대적으로 일치합니다 . 매처는 줄 종결자를 무시합니다.

@Test
public void givenRegex_whenMatchFailsWithoutMultilineFlag_thenCorrect() {
    int matches = runTest(
      "dog$", "This is a dog" + System.getProperty("line.separator") 
      + "this is a fox");
 
    assertFalse(matches > 0);
}

매처가 전체 문자열 의 끝에서 dog 를 검색 하지만 문자열 의 첫 줄 끝에 dog 가 있기 때문에 이 일치는 실패 합니다.

그러나 플래그를 사용하면 매처가 이제 줄 종결자를 고려하므로 동일한 테스트가 통과됩니다. 따라서 문자열 는 줄이 끝나기 직전에 발견되며 이는 성공을 의미합니다.

@Test
public void givenRegex_whenMatchesWithMultilineFlag_thenCorrect() {
    int matches = runTest(
      "dog$", "This is a dog" + System.getProperty("line.separator") 
      + "this is a fox", Pattern.MULTILINE);
 
    assertTrue(matches > 0);
}

임베디드 플래그 버전은 다음과 같습니다.

@Test
public void givenRegex_whenMatchesWithEmbeddedMultilineFlag_
  thenCorrect() {
    int matches = runTest(
      "(?m)dog$", "This is a dog" + System.getProperty("line.separator") 
      + "this is a fox");
 
    assertTrue(matches > 0);
}

12. 매처 클래스 메서드

이 섹션에서는 Matcher 클래스 의 유용한 메서드에 대해 알아봅니다 . 명확성을 위해 기능에 따라 그룹화합니다.

12.1. 색인 방법

인덱스 메서드는 입력 String 에서 일치 항목을 찾을 위치를 정확하게 보여주는 유용한 인덱스 값을 제공합니다 . 다음 테스트 에서는 입력 문자열 에서 dog 일치의 시작 및 종료 인덱스를 확인합니다 .

@Test
public void givenMatch_whenGetsIndices_thenCorrect() {
    Pattern pattern = Pattern.compile("dog");
    Matcher matcher = pattern.matcher("This dog is mine");
    matcher.find();
 
    assertEquals(5, matcher.start());
    assertEquals(8, matcher.end());
}

12.2. 연구 방법

연구 방법은 입력 문자열 을 통과 하고 패턴이 발견되었는지 여부를 나타내는 부울을 반환합니다. 일반적으로 사용되는 것은 matcheslookingAt 메소드입니다.

matcheslookingAt 메소드 는 둘 다 패턴에 대해 입력 시퀀스를 일치시키려고 시도합니다. 차이점은 일치 는 전체 입력 시퀀스가 ​​일치해야 하지만 lookingAt 는 일치 하지 않는다는 것입니다.

두 방법 모두 입력 문자열 의 시작 부분에서 시작합니다 .

@Test
public void whenStudyMethodsWork_thenCorrect() {
    Pattern pattern = Pattern.compile("dog");
    Matcher matcher = pattern.matcher("dogs are friendly");
 
    assertTrue(matcher.lookingAt());
    assertFalse(matcher.matches());
}

matches 메서드는 다음과 같은 경우에 true를 반환합니다.

@Test
public void whenMatchesStudyMethodWorks_thenCorrect() {
    Pattern pattern = Pattern.compile("dog");
    Matcher matcher = pattern.matcher("dog");
 
    assertTrue(matcher.matches());
}

12.3. 교체 방법

교체 방법은 입력 문자열의 텍스트를 교체하는 데 유용합니다. 일반적인 것은 replaceFirstreplaceAll 입니다.

replaceFirstreplaceAll 메서드 는 지정된 정규식과 일치하는 텍스트를 바꿉니다. 이름에서 알 수 있듯이 replaceFirst 는 첫 번째 항목을 대체하고 replaceAll 은 모든 항목을 대체합니다.

@Test
public void whenReplaceFirstWorks_thenCorrect() {
    Pattern pattern = Pattern.compile("dog");
    Matcher matcher = pattern.matcher(
      "dogs are domestic animals, dogs are friendly");
    String newStr = matcher.replaceFirst("cat");
 
    assertEquals(
      "cats are domestic animals, dogs are friendly", newStr);
}

모든 항목 바꾸기:

@Test
public void whenReplaceAllWorks_thenCorrect() {
    Pattern pattern = Pattern.compile("dog");
    Matcher matcher = pattern.matcher(
      "dogs are domestic animals, dogs are friendly");
    String newStr = matcher.replaceAll("cat");
 
    assertEquals("cats are domestic animals, cats are friendly", newStr);
}

replaceAll 메소드를 사용 하면 모든 일치 항목을 동일한 대체 항목으로 대체할 수 있습니다. 경우에 따라 일치 항목을 교체하려면 토큰 교체 기술 이 필요합니다 .

13. 결론

이 기사에서는 Java에서 정규식을 사용하는 방법을 배웠습니다. 또한 java.util.regex 패키지 의 가장 중요한 기능에 대해서도 살펴보았습니다 .

여기에 사용된 모든 코드 샘플을 포함하여 프로젝트의 전체 소스 코드는 GitHub 프로젝트 에서 찾을 수 있습니다 .

Generic footer banner