캡처 그룹(Capturing Group)이란?
정규식에서 캡처 그룹(capturing group)을 사용하면 여러 문자를 하나의 단위로 묶어 다룰 수 있습니다. 그룹으로 지정하고 싶은 문자들을 괄호 () 안에 넣기만 하면 됩니다.
(.*)(\\d+)(.*)
여러 개의 그룹을 사용해 매칭하면 각 그룹의 매칭 결과가 개별적으로 저장됩니다. Matcher 객체의 group() 메서드에 해당 그룹 번호를 전달하면 결과를 조회할 수 있으며, 그룹 번호는 왼쪽 괄호부터 순서대로 1, 2, 3…으로 매겨집니다. 그룹 0은 패턴 전체의 매칭 결과를 나타냅니다.
예제 코드
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CapturingGroups {
public static void main(String args[]) {
System.out.println("Enter input text");
Scanner sc = new Scanner(System.in);
String input = sc.nextLine();
String regex = "(.*)(\\d+)(.*)";
// Pattern 객체 생성
Pattern pattern = Pattern.compile(regex);
// Matcher 객체 생성
Matcher matcher = pattern.matcher(input);
if (matcher.find()) {
System.out.println("Found value: " + matcher.group(0));
System.out.println("Found value: " + matcher.group(1));
System.out.println("Found value: " + matcher.group(2));
System.out.println("Found value: " + matcher.group(3));
} else {
System.out.println("NO MATCH");
}
}
}
실행 결과
Enter input text sample data with 1234 (digits) in middle Found value: sample data with 1234 (digits) in middle Found value: sample data with 123 Found value: 4 Found value: (digits) in middle
실행 결과를 보면 첫 번째 그룹 (.*)는 탐욕적(greedy)으로 동작하기 때문에 숫자 가운데 마지막 한 글자만 남기고 최대한 많은 부분을 가져갑니다. 따라서 group(1)은 'sample data with 123'이 되고, \d+는 남은 '4'만 매칭하며, 세 번째 그룹은 나머지 '(digits) in middle'을 담게 됩니다.
비캡처 그룹(Non-Capturing Group)
비캡처 그룹(non-capturing group)은 캡처 그룹과 동일하게 여러 문자를 하나의 단위로 묶는 기능을 제공하지만, 매칭 결과를 별도로 저장하지 않는 그룹입니다.
예를 들어 텍스트에서 URL이나 전화번호를 그룹을 이용해 찾는 경우를 생각해 봅시다. 찾으려는 부분 문자열들의 시작 부분이 서로 같다면 일부 그룹의 결과를 굳이 저장할 필요가 없는데, 이럴 때 비캡처 그룹을 활용하면 좋습니다. 비캡처 그룹은 (?:로 시작하여 )로 끝납니다.
비캡처 그룹을 사용하면 불필요한 결과 저장이 줄어들어 메모리를 절약할 수 있고, 그룹 번호 관리도 더 단순해진다는 장점이 있습니다.
예제 코드
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class NonCapturingGroups {
public static void main(String args[]) {
System.out.println("Enter input text");
Scanner sc = new Scanner(System.in);
String input = sc.nextLine();
String regex = "(.*)(?:\\d+)(.*)";
// Pattern 객체 생성
Pattern pattern = Pattern.compile(regex);
// Matcher 객체 생성
Matcher matcher = pattern.matcher(input);
if (matcher.find()) {
System.out.println("Found value: " + matcher.group(0));
System.out.println("Found value: " + matcher.group(1));
System.out.println("Found value: " + matcher.group(2));
} else {
System.out.println("NO MATCH");
}
}
}
실행 결과
Enter input text sample data with 1234 (digits) in middle Found value: sample data with 1234 (digits) in middle Found value: sample data with 123 Found value: (digits) in middle
참고: 비캡처 그룹은 그룹 개수에 포함되지 않습니다. 즉, 위 예제에서 groupCount()를 호출하면 비캡처 그룹을 제외한 2가 반환됩니다.