Computer >> 컴퓨터 >  >> 프로그래밍 >> Java

자바(Java) 정규식의 세 가지 수량자 유형 – 탐욕적, 게으른, 소유적 수량자 완벽 이해

정규 표현식을 작성할 때 특정 패턴이 반복되는 횟수를 지정해야 하는 경우가 많습니다. 이럴 때 사용하는 것이 바로 수량자(Quantifier)입니다. 자바는 크게 세 가지 유형의 수량자를 지원하며, 각각 탐욕적(Greedy) 수량자, 게으른(Reluctant) 수량자, 그리고 소유적(Possessive) 수량자라고 부릅니다.

1. 탐욕적(Greedy) 수량자

탐욕적 수량자는 별도의 표기 없이 기본적으로 적용되는 수량자입니다. 이름처럼 '탐욕스럽게' 동작하여 입력 문자열에서 가능한 한 가장 긴 매칭(longest match)을 찾으려고 시도합니다. 만약 매칭에 실패하면 마지막 문자 하나를 제외하고 다시 매칭을 시도하는 방식(백트래킹)으로 동작합니다.

예제

import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Enter input text: ");
        String input = sc.nextLine();

        String regex = "[0-9]+";

        // 패턴 객체 생성
        Pattern pattern = Pattern.compile(regex);

        // 문자열에서 컴파일된 패턴과 매칭
        Matcher matcher = pattern.matcher(input);

        System.out.println("Matched text:");
        while (matcher.find()) {
            System.out.println(matcher.group());
        }
    }
}

실행 결과

Enter input text:
45545
Matched text:
45545

위 예제에서 [0-9]+는 숫자가 연속으로 등장하는 가장 긴 문자열 전체를 한 번에 매칭합니다. 이것이 바로 탐욕적 수량자의 특징입니다.

2. 게으른(Reluctant) 수량자

게으른 수량자는 비탐욕적(non-greedy) 수량자라고도 하며, 탐욕적 수량자와 정반대로 최소한만큼만 매칭합니다. 처음에는 첫 번째 문자만으로 매칭을 시도하고, 실패할 경우 입력 문자열에서 문자를 하나씩 추가하며 다시 시도합니다.

탐욕적 수량자 뒤에 물음표(?)를 붙이면 게으른 수량자로 변경됩니다. 예를 들어 +?, *?, ??와 같이 사용합니다.

예제

import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Enter input text: ");
        String input = sc.nextLine();

        String regex = "[0-9]+?";

        // 패턴 객체 생성
        Pattern pattern = Pattern.compile(regex);

        // 문자열에서 컴파일된 패턴과 매칭
        Matcher matcher = pattern.matcher(input);

        while (matcher.find()) {
            System.out.println(matcher.group());
        }
    }
}

실행 결과

Enter input text:
12345678
1
2
3
4
5
6
7
8

[0-9]+?는 최소 한 개의 숫자만 매칭하려고 하므로, 입력된 숫자들이 각각 하나씩 분리되어 출력됩니다.

3. 소유적(Possessive) 수량자

소유적 수량자는 동작 방식이 탐욕적 수량자와 유사하지만 결정적인 차이가 있습니다. 소유적 수량자는 처음부터 가능한 한 많은 문자를 매칭하며, 매칭에 실패했을 때 탐욕적 수량자와 달리 백트래킹을 하지 않습니다. 즉, 한번 잡은 문자를 놓아주지 않기 때문에 '소유적'이라는 이름이 붙었습니다.

탐욕적 수량자 뒤에 플러스(+)를 붙이면 소유적 수량자가 됩니다. 대표적인 소유적 수량자로는 *+, ++, ?+, {n}+ 등이 있습니다.

예제

import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Test {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("Enter input text: ");
        String input = sc.nextLine();

        String regex = "[0-9]++";

        // 패턴 객체 생성
        Pattern pattern = Pattern.compile(regex);

        // 문자열에서 컴파일된 패턴과 매칭
        Matcher matcher = pattern.matcher(input);

        while (matcher.find()) {
            System.out.println(matcher.group());
        }
    }
}

실행 결과

Enter input text:
45678
45678

입력된 숫자 문자열 전체가 한 번에 매칭되어 출력됩니다. 백트래킹이 발생하지 않으므로 불필요한 재시도 없이 빠르게 처리됩니다.

마무리: 세 가지 수량자 비교 요약

수량자 유형표기법동작 방식
탐욕적(Greedy)X+, X*, X?가장 길게 매칭 시도 후, 실패 시 백트래킹
게으른(Reluctant)X+?, X*?, X??가장 짧게 매칭 시도 후, 필요 시 확장
소유적(Possessive)X++, X*+, X?+가장 길게 매칭 시도, 백트래킹 없음

세 수량자의 차이를 이해하면 정규식의 성능을 최적화하고 의도치 않은 매칭 오류를 방지할 수 있습니다. 특히 대용량 텍스트를 처리할 때는 백트래킹을 하지 않는 소유적 수량자가 성능 면에서 유리할 수 있다는 점을 기억해 두세요.