[JAVA] 정규 표현식, Pattern 클래스로 쉽게 이용해보자! (Pattern.quote()를 중점적으로)

2025. 10. 17. 21:44·Java & Kotlin

들어가며

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

 

본론으로

만약 정규식 자체가 궁금하다면 아래의 블로그를 참고하면 될 것 같다. 너무너무 정리가 깔끔하게 잘 되어있다.

https://gngsn.tistory.com/51

 

정규식, 어렵지 않게 사용하기 - 기본

알고리즘을 하다보면 한 번쯤 정규식을 사용해보셨을 것 같아요. 혹은 한 번쯤 들어봤을 법한데요. 오늘은 정규식을 파헤쳐보는 시간을 갖겠습니다 ✨ **************** 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
'Java & Kotlin' 카테고리의 다른 글
  • [JAVA] Collection의 복사 방법에 대해 알아보자!(방어적 복사, 얕은 복사, 깊은 복사) feat. 내가 List.copyOf와 Arrays.asList를 쓴 이유
  • [JAVA] split() 메서드 정복하기 (나는 왜 split(delimiter, -1)을 썻을까?)
  • [JAVA] 일급 콜렉션을 이용하여 상태와 로직을 따로 관리하자!
  • [JAVA] final 키워드 정복하기!
노을을
노을을
진인사대천명
  • 노을을
    노을의 개발일기장
    노을을
  • 전체
    오늘
    어제
    • All (61) N
      • Java & Kotlin (16)
      • Spring (3) N
      • Problem Solve (13) N
      • Computer Science (0)
      • Infra (1)
      • DB (2)
      • Various Dev (23)
        • 우아한테크코스 (9)
        • Git&Github (2)
        • Unity (12)
      • Book (1)
      • Writing (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    github
    우테코
    개발자
    게임개발
    우아한테크코스
    개발
    프리코스
    알고리즘
    자바
    java
    코딩테스트
    오픈미션
    코테
    합격
    백준
    유니티
    코딩
    8기
    스프링
    티스토리챌린지
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
노을을
[JAVA] 정규 표현식, Pattern 클래스로 쉽게 이용해보자! (Pattern.quote()를 중점적으로)
상단으로

티스토리툴바