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

Java 정규식(Regex)에서 캡처 그룹(Capturing Group)이란 무엇일까?

정규 표현식(Regex)이란?

정규 표현식은 패턴에 담긴 특수한 문법을 사용해 다른 문자열이나 문자열 집합을 찾아내거나 일치 여부를 확인하는 데 활용되는 특수 문자 시퀀스입니다.

캡처 그룹(Capturing Group)의 의미

정규식에서 캡처 그룹은 여러 문자를 하나의 단위로 다루기 위한 기능으로, 괄호 ()로 표현합니다. 즉, 괄호 안에 여러 개의 하위 패턴을 넣으면 해당 부분이 하나의 그룹으로 묶이고, 매칭 결과를 그룹 단위로 추출할 수 있습니다.

예를 들어 [0-9]는 0부터 9 사이의 숫자 한 자리와 일치하고, 수량자 {5}는 바로 앞의 요소가 정확히 5번 반복됨을 의미합니다. 이 둘을 ([0-9]{5})처럼 그룹으로 묶으면 "5자리 숫자"와 일치하는 패턴이 됩니다.

예제 1: Pattern.COMMENTS 플래그로 가독성 높이기

Java의 Pattern.COMMENTS 플래그를 사용하면 정규식 내부에 #으로 시작하는 주석을 작성할 수 있어, 복잡한 패턴도 훨씬 읽기 쉽게 관리할 수 있습니다. 아래 예제는 MM/DD/YYYY 형식의 생년월일 유효성을 검사합니다.

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

public class CommentExample {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("이름을 입력하세요: ");
        String name = sc.nextLine();
        System.out.println("생년월일을 입력하세요: ");
        String dob = sc.nextLine();

        // MM/DD/YYYY 형식의 날짜를 검사하는 정규식
        String regex = "^(1[0-2]|0[1-9])/   # 월(Month)\n"
            + "(3[01]|[12][0-9]|0[1-9])/ # 일(Day)\n"
            + "[0-9]{4}$                  # 연도(Year)";

        // Pattern 객체 생성
        Pattern pattern = Pattern.compile(regex, Pattern.COMMENTS);
        // Matcher 객체 생성
        Matcher matcher = pattern.matcher(dob);
        boolean result = matcher.matches();

        if(result) {
            System.out.println("입력한 생년월일은 유효합니다.");
        } else {
            System.out.println("입력한 생년월일이 유효하지 않습니다.");
        }
    }
}

실행 결과

이름을 입력하세요:
Krishna
생년월일을 입력하세요:
09/26/1989
입력한 생년월일은 유효합니다.

예제 2: group() 메서드로 캡처 그룹 확인하기

Matcher 객체의 group() 메서드를 사용하면 각 그룹에 매칭된 문자열을 확인할 수 있습니다. group(0)은 전체 매칭 결과를 반환하고, group(1)부터는 왼쪽 괄호 순서대로 첫 번째, 두 번째, 세 번째 그룹의 결과를 반환합니다.

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

public class GroupTest {
    public static void main(String[] args) {
        String regex = "(.*)(\\d+)(.*)";
        String input = "This is a sample Text, 1234, with numbers in between.";

        // Pattern 객체 생성
        Pattern pattern = Pattern.compile(regex);
        // 문자열에서 컴파일된 패턴과 매칭 수행
        Matcher matcher = pattern.matcher(input);

        if(matcher.find()) {
            System.out.println("전체 매칭: " + matcher.group(0));
            System.out.println("첫 번째 그룹: " + matcher.group(1));
            System.out.println("두 번째 그룹: " + matcher.group(2));
            System.out.println("세 번째 그룹: " + matcher.group(3));
        }
    }
}

실행 결과

전체 매칭: This is a sample Text, 1234, with numbers in between.
첫 번째 그룹: This is a sample Text, 123
두 번째 그룹: 4
세 번째 그룹: , with numbers in between.

위 결과에서 첫 번째 그룹 (.*)는 탐욕적(greedy) 방식으로 동작하기 때문에 가능한 한 많은 문자를 차지하려 합니다. 그 결과 "This is a sample Text, 123"까지를 가져가고, 숫자 그룹 (\d+)에는 마지막 한 글자 "4"만 남게 되는 것입니다. 이처럼 캡처 그룹을 활용하면 전체 매칭 결과 중 필요한 부분만 손쉽게 분리해 사용할 수 있습니다.