들어가며
우테코 프리코스 1주차 문제를 풀던 중 정규 표현식에 대해서 고민해볼 포인트가 생겼다. 정규표현식 대충 알고만 있었는데, 사실 알아도 활용하기는 조금 어려운 것이 사실인 것 같다. 이런 부분을 도와주고자 자바는 Pattern 클래스를 제공한다. 문제 풀며 고민했던 점과 함께 풀어 나가보자!

본론으로
만약 정규식 자체가 궁금하다면 아래의 블로그를 참고하면 될 것 같다. 너무너무 정리가 깔끔하게 잘 되어있다.
정규식, 어렵지 않게 사용하기 - 기본
알고리즘을 하다보면 한 번쯤 정규식을 사용해보셨을 것 같아요. 혹은 한 번쯤 들어봤을 법한데요. 오늘은 정규식을 파헤쳐보는 시간을 갖겠습니다 ✨ **************** INDEX ***************** 🌈 정규식
gngsn.tistory.com
Pattern 클래스는 java.util.regex 패키지에 포함되어 있다.
다양한 메서드를 제공하는데, 이름부터가 어떠한가! 그렇다 정규식 표현자체를 저장해주고 우리가 원하는 식으로 매핑이 가능하다.
간단하게 아래 코드를 보자.
import java.util.regex.Pattern;
public class RegexDemo {
public static void main(String[] args) {
// 이메일 주소 (간단·실용 버전)
String REGEX = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
String INPUT1 = "noeul.dev+test@gmail.com"; // 정확히 이메일만 → true
String INPUT2 = "연락은 noeul.dev+test@gmail.com 으로 주세요"; // 문장 포함 → false
System.out.println(Pattern.matches(REGEX, INPUT1)); // true
System.out.println(Pattern.matches(REGEX, INPUT2)); // false
}
}
String으로 들어온 정규표현식(REGEX)를 Pattern에 담아 INPUT1로 만들었고 정규표현식에 다른 문장이 추가된 문장을 INPUT2로 만들었다.
Patterns.matches의 결과를 보면 정규표현식과 일치하는 INPUT1은 true, 일치하지 않는 것은 false를 출력함을 알 수 있다. 다양한 메서드의 활용은 아래 글의 이해하기 쉽게 잘 설명되어 있다.
https://gngsn.tistory.com/53#google_vignette
Pattern, 어렵지 않게 사용하기
안녕하세요. 이전 포스팅에서 알아본 정규식을 활용하여 java에서 사용하는 방법을 알아보려합니다. 정규식이 낯설다면 이전의 정규식 포스팅을 참고해주세요! **************** 참고 ***************** **
gngsn.tistory.com
이처럼 Pattern은 정규표현식을 개발자가 조금 더 활용하기 쉽게끔 지원해준다!!(사실.. 정규 표현식 자체가.. 좀 어렵긴하다.) 나는 내가 이 클래스를 쓴 이유를 중점적으로 이야기 해보고자 한다.
내가 문제를 풀다가 Pattern 클래스를 쓴 이유는 무엇일까?
1주차 문제는 간단하게 문자열을 (기본 구분자 + 커스텀 구분자)로 쪼개서 안의 숫자들을 구해 합산을 구하는 문제였다. 처음에는 split()함수의 delimiter를 ", | ; | @ | ." 식으로 OR 연산자로 연결해서 줄 수 있길래, "." + "|" + "?" 처럼 문자열 + 연산자를 통해서 delimiter를 만들 생각이었다!! 하지만 나는 아래처럼 Pattern 클래스의 quote()를 이용하여 delimiter를 만들어서 반환하는 함수를 적용하였다. 왤까?
private static String makeDelimiter(char input) {
return BASE_DELIMITER + "|" + Pattern.quote(String.valueOf(input));
}
코드를 리팩토링하려고 많은 검색을 거친 결과 정규식 표현이라는 개념을 보게 되었다. 결론 먼저 말하자면 아래와 같은 이유로 사용한 것이다.
커스텀 구분자에 [ 같은 정규식 메타문자가 들어올 수 있어서, 그걸 “문자 그대로” 취급시키려고 Pattern.quote를 썼다.
"메타 문자가 뭐지?" “정규식이 [로 시작하나?” 다른건 되는 거 아니야? -> 위치와 무관해도 문제가 생긴다!
조금만 더 정확히 풀어보자.
정규식 엔진은 패턴 전체를 해석한다. 우리가 만들 패턴이 ",|:|[" 처럼 어디에든 [가 들어가면, 그건 “문자 클래스 시작”으로 읽혀서 아래와 같은 해석 오류가 발생한다.
- 닫히는 ]가 없으면: 문법 오류 (PatternSyntaxException: Unclosed character class)
- 닫혀 있다면: 집합으로 해석("[abc]" → a, b, c 중 하나)
즉, “패턴이 [로 시작하느냐”가 아니라, 패턴 안에 있는 [ 자체가 메타문자라서 문제가 생긴다.

그럼 여기서! 메타문자란?
정규식에서 특별한 의미를 가진 문자들이다.
- 문자클래스/경계/그룹/수량자/논리
[](문자집합), ()(그룹), {}(수량), .(임의의 1글자), * + ?(반복), ^ $(문자열 시작/끝), |(OR), \(이스케이프) - 이 문자들이 그냥 글자로 쓰이길 원하면 이스케이프가 필요하다. -> 사실 이 이스케이프를 처리하기 굉장히 싫었다. case문 덕지덕지.. if문 길어지고... 코드가 너무 길어졌다
그럼 Pattern.quote()가 뭐길래??
-> Pattern.quote(s)는 입력을 \Q ... \E로 감싸서 정규식 문법을 전부 무력화해해준다. -> WOW!!
- 예) Pattern.quote("[") → \Q[\E (엔진에겐 그냥 리터럴)
- 예) Pattern.quote(".") → \Q.\E (임의의 1글자 → 점 문자 그대로)
그래서 커스텀 구분자가 무엇이든(심지어 . * | [ 등) 항상 안전하다.
만약 pattern.quote()를 안썻다면...
- 커스텀 [ : ",|:|[" → 문법 오류(닫히지 않은 문자 클래스)
- 커스텀 . : ",|:|." → 모든 글자를 구분자로 매칭됨(의도와 다름)
- 커스텀 | : ",|:||" → “빈 패턴” 포함돼서 모든 위치에서 매칭 (전부 쪼개짐)
- 커스텀 \ : 이스케이프 문맥 깨져 문법 오류 가능.
요약 한 줄
- [는 정규식에서 문자 클래스 시작이기 때문에, 커스텀 구분자로 들어오면 패턴이 깨질 수 있다.
- 그래서 우리는 Pattern.quote로 메타문자를 리터럴화해서 안전하고 단순하게 처리한 것이다.
마무리하며
앞으로 문자 기호 관련해서 애매한 일이 생긴다면 Pattern 인터페이스의 quote() 메서드를 적극 활용할 듯 싶다. 아직은 문자열 표현을 정규식으로 바꿀일이 있을까? 싶다만,, 정규식이 뭔지는 알고!! 정규식을 피할수도 있어졌다!! 다음에도 민감한 메타문자가 매개변수로 넘어올 순간이 생기면 Pattern.quote()로 벗겨주자!!!

'Java & Kotlin' 카테고리의 다른 글
| [JAVA] Collection의 복사 방법에 대해 알아보자!(방어적 복사, 얕은 복사, 깊은 복사) feat. 내가 List.copyOf와 Arrays.asList를 쓴 이유 (0) | 2025.10.18 |
|---|---|
| [JAVA] split() 메서드 정복하기 (나는 왜 split(delimiter, -1)을 썻을까?) (1) | 2025.10.17 |
| [JAVA] 일급 콜렉션을 이용하여 상태와 로직을 따로 관리하자! (0) | 2025.10.17 |
| [JAVA] final 키워드 정복하기! (0) | 2025.10.16 |
| [JAVA] 정적 중첩 클래스를 활용하여 계층간 독립적인 Validation을 적용해보자 (0) | 2025.10.16 |