quoteReplacement() 메서드란?
Java 정규식 처리 시 Matcher 클래스의 appendReplacement() 메서드는 StringBuffer 객체와 대체 문자열(replacement string)을 매개변수로 받아, 입력 데이터를 StringBuffer에 추가하면서 일치된 내용을 대체 문자열로 교체하는 역할을 합니다.
내부적으로 이 메서드는 입력 문자열에서 한 문자씩 읽어 버퍼에 추가하다가, 일치(match)가 발견되면 일치된 부분 대신 대체 문자열을 버퍼에 넣고, 일치한 하위 문자열의 다음 위치부터 계속 진행합니다.
그런데 이 메서드에 대체 문자열을 전달할 때 슬래시(/)나 달러 기호($)가 포함되어 있으면 일반 문자로 취급되지 않고 아래와 같은 예외가 발생합니다.
예제 1 — 특수문자 사용 시 발생하는 오류
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class QuoteReplacement {
public static void main(String[] args) {
String str = " <p>This <b>is</b> an <b>example</b> HTML <b>script</b>.</p>";
// 굵은 글씨(bold) 태그 내용을 찾기 위한 정규식
String regex = "<b>(\\S+)</b>";
System.out.println("Input string: \n"+str);
// Pattern 객체 생성
Pattern pattern = Pattern.compile(regex);
// 컴파일된 패턴을 문자열에 적용
Matcher matcher = pattern.matcher(str);
// 빈 StringBuffer 생성
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, "sampledata$" );
//Matcher.quoteReplacement("Bo$ld/Data$"));
}
matcher.appendTail(sb);
System.out.println("Contents of the StringBuffer: \n"+ sb.toString() );
}
}실행 결과
Input string:
<p>This <b>is</b> an <b>example</b> HTML <b>script</b>.</p>
Exception in thread "main" java.lang.IllegalArgumentException: Illegal group reference: group index is missing
at java.util.regex.Matcher.appendReplacement(Unknown Source)
at OCTOBER.matcher.QuoteReplacement.main(QuoteReplacement.java:18)위 실행 결과에서 볼 수 있듯이, 대체 문자열에 $ 기호가 포함되면 Illegal group reference 예외가 발생합니다. 이는 $가 정규식에서 그룹 참조(group reference)를 의미하기 때문입니다.
해결 방법 — quoteReplacement() 메서드 활용
Matcher 클래스의 quoteReplacement() 메서드는 문자열 값을 받아 리터럴(literal) 대체 문자열을 반환합니다. 즉, 주어진 문자열에서 /와 $ 문자가 일반 문자로 취급되며, 반환된 결과는 appendReplacement() 메서드의 매개변수로 안전하게 사용할 수 있습니다.
예제 2 — quoteReplacement() 적용 후 정상 동작
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class QuoteReplacement {
public static void main(String[] args) {
String str = "<p>This <b>is</b> an <b>example</b> HTML <b>script</b>.</p>";
// 굵은 글씨(bold) 태그 내용을 찾기 위한 정규식
String regex = "<b>(\\S+)</b>";
System.out.println("Input string: \n"+str);
// Pattern 객체 생성
Pattern pattern = Pattern.compile(regex);
// 컴파일된 패턴을 문자열에 적용
Matcher matcher = pattern.matcher(str);
// 빈 StringBuffer 생성
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, Matcher.quoteReplacement("Bo$ld/Data$"));
}
matcher.appendTail(sb);
System.out.println("Contents of the StringBuffer: \n"+ sb.toString() );
}
}실행 결과
Input string: <p>This <b>is</b> an <b>example</b> HTML <b>script</b>.</p> Contents of the StringBuffer: <p>This Bo$ld/Data$ an Bo$ld/Data$ HTML Bo$ld/Data$.</p>
Matcher.quoteReplacement()를 적용하자 $와 /가 특수문자가 아닌 일반 문자열로 처리되어, 더 이상 예외 없이 의도한 대로 치환이 완료된 것을 확인할 수 있습니다.
예제 3 — quoteReplacement() 단독 사용
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class QuoteReplacementExample {
public static void main(String[] args) {
String input = "This is sample text";
String regex = "[#]";
// Pattern 객체 생성
Pattern pattern = Pattern.compile(regex);
// 컴파일된 패턴을 문자열에 적용
Matcher matcher = pattern.matcher(input);
// 빈 StringBuffer 생성
String str = Matcher.quoteReplacement("sampledata");
System.out.println(str);
}
}실행 결과
sampledata
정리
appendReplacement() 사용 시 대체 문자열에 $나 / 같은 특수문자가 포함될 가능성이 있다면, 반드시 Matcher.quoteReplacement()로 감싸서 전달하는 것이 안전합니다. 이를 통해 IllegalArgumentException과 같은 런타임 예외를 예방하고, 사용자 입력값을 치환 문자열로 사용할 때도 안정적으로 처리할 수 있습니다.