정규 표현식(Regular Expression)은 특수한 문법으로 구성된 문자열 패턴을 통해 다른 문자열이나 문자열 집합을 검색하거나 찾아낼 수 있게 해주는 강력한 도구입니다. 이를 활용하면 텍스트와 데이터를 손쉽게 검색, 편집, 조작할 수 있습니다. Java는 java.util.regex 패키지를 통해 정규식 기반의 패턴 매칭 기능을 기본적으로 제공합니다.
Matcher 클래스란?
Matcher 객체는 컴파일된 패턴을 해석하고 입력 문자열에 대해 매칭 작업을 수행하는 엔진 역할을 합니다. Pattern 클래스와 마찬가지로 Matcher 클래스도 public 생성자를 제공하지 않습니다. 대신 Pattern 객체의 matcher() 메서드를 호출하여 Matcher 객체를 얻을 수 있습니다.
여기서 중요한 점은 다음과 같습니다.
"Matcher 클래스의 인스턴스는 여러 스레드가 동시에 사용하기에 안전하지 않습니다."
Pattern과 Matcher의 스레드 안전성 차이
흥미롭게도 두 클래스의 스레드 안전성은 서로 다릅니다.
- Pattern 클래스: 불변(immutable) 객체이므로 스레드로부터 안전합니다. 따라서 하나의 Pattern 객체를 여러 스레드가 공유해도 문제없습니다.
- Matcher 클래스: 매칭 진행 상태를 내부적으로 유지하는 가변(mutable) 객체이므로 스레드에 안전하지 않습니다. 각 스레드는 반드시 자신만의 Matcher 인스턴스를 생성해서 사용해야 합니다.
따라서 멀티스레드 환경에서는 Pattern 객체를 공유하되, 각 스레드마다 별도의 Matcher 객체를 만들어 사용하는 것이 올바른 방법입니다.
예제 코드
다음 Java 프로그램은 사용자로부터 5개의 문자열을 입력받아, 숫자로 시작하는 문자열만 골라 출력합니다.
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StartingwithDigit {
public static void main(String args[]) {
String regex = "^[0-9].*$";
Scanner sc = new Scanner(System.in);
System.out.println("Enter 5 input strings: ");
String input[] = new String[5];
for (int i = 0; i < 5; i++) {
input[i] = sc.nextLine();
}
// Pattern 객체 생성
Pattern p = Pattern.compile(regex);
System.out.println("Strings starting with digits: ");
for (int i = 0; i < 5; i++) {
// Matcher 객체 생성
Matcher m = p.matcher(input[i]);
if (m.matches()) {
System.out.println(m.group());
}
}
}
}실행 결과
Enter 5 input strings: sample string 1 sample string 2 11 sample string 3 22 sample string 4 43534 56353 636 Strings starting with digits: 11 sample string 3 22 sample string 4 43534 56353 636
정리
Java의 Matcher 클래스는 내부 상태를 유지하기 때문에 멀티스레드 환경에서 안전하지 않습니다. 반면 Pattern 클래스는 불변 객체이므로 자유롭게 공유할 수 있습니다. 멀티스레드 애플리케이션에서 정규식을 사용할 때는 이 차이를 반드시 기억하고, 스레드별로 Matcher 인스턴스를 분리하여 사용하는 것이 좋습니다.