IMG-LOGO
공지사항 :

정규표현식(Regular Expressions) 패턴

lmkfox - 2025-09-20 06:29:45 73 Views 0 Comment

1) 기본 메타문자(요약)

.      : 줄바꿈 문자를 제외한 임의의 한 문자
^ $    : 문자열의 시작/끝 (문맥에 따라 줄 시작/끝)
* + ?  : 0회 이상 / 1회 이상 / 0 or 1
{n} {n,} {n,m} : 정확히 n, n회 이상, n~m회 반복
[]     : 문자 클래스 (예: [a-zA-Z0-9])
[^...] : 부정 문자 클래스
|      : OR (alternation)
()     : 그룹(캡쳐)
(?: )  : 비캡처 그룹
\      : 이스케이프 (특수문자를 문자로 취급)
\w \W  : 단어 문자 / 비단어 문자
\d \D  : 숫자 / 비숫자
\s \S  : 공백 / 비공백
\b \B  : 단어 경계 / 비단어 경계


2) 앵커와 경계

  • ^ : 문자열(또는 multiline에서 줄)의 시작

  • $ : 문자열(또는 multiline에서 줄)의 끝

  • \A : 입력의 시작(항상)

  • \z : 입력의 끝(항상)

  • \Z : 입력 끝 또는 끝 앞의 최종 줄바꿈

  • \b : 단어 경계 — 단어 문자와 비단어 문자 사이

  • \B : 단어 경계가 아닌 곳


3) 그룹과 캡처

  • (pattern) : 캡처 그룹 — 이후 \1, \2 등으로 참조 가능

  • (?:pattern) : 비캡처 그룹 — 그룹화는 하지만 캡처 안 함(성능·명확성에 유리)

  • 이름 있는 그룹:

    • PCRE / JS(ES2018+) / Java: (?<name>...)

    • Python: (?P<name>...)

    • 역참조: \k<name> 또는 Python의 (?P=name)

예:

(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})


4) 수량자(Quantifiers) — 탐욕성 vs 최소매칭

  • 탐욕적(Greedy): *, +, ?, {m,n} — 가능한 한 많이 매칭

  • 최소(Non-greedy / Lazy): *?, +?, ??, {m,n}? — 가능한 한 적게 매칭

  • 소유적(Possessive, Java/PCRE 일부): *+, ++, ?+, {m,n}+ — 백트래킹을 허용하지 않음(성능 보장)

예 — 태그 매칭:

<.+>     // 탐욕적: "<a>text</a>" 전체를 매칭
<.+?>    // 최소: "<a>" 와 "</a>"를 각각 정확히 매칭


5) 어서션(Assertions, Lookaround) — 뒤/앞 조건

  • 전방 긍정: (?=...) — 뒤에 특정 패턴이 오는 경우

  • 전방 부정: (?!...) — 뒤에 특정 패턴이 오지 않는 경우

  • 후방 긍정: (?<=...) — 앞에 특정 패턴이 있는 경우

  • 후방 부정: (?<!...) — 앞에 특정 패턴이 없는 경우

예:

\d+(?=USD)    // "100USD"에서 "100"을 캡처(뒤에 USD가 있어야)
(?<=USD)\d+    // "USD100"에서 "100"을 캡처(앞에 USD 있어야)

주의: 일부 엔진(JavaScript 오래된 버전 등)은 lookbehind를 지원하지 않습니다. 또한 일부 엔진은 lookbehind에 고정 길이만 허용합니다.


6) 플래그(Modifiers)

  • i : 대소문자 무시 (case-insensitive)

  • m : multiline — ^/$가 줄별 경계로 동작

  • s : dotall — .가 줄바꿈도 포함하게 함

  • x : verbose / free-spacing — 공백·주석 허용(가독성 높임, Python re.X)

  • u : Unicode 모드 (언어별 차이 있음)

  • g : global (검색/치환에서 모든 매칭; JS에서 사용)

인라인 선언:

(?i)pattern      // 패턴 전체에 case-insensitive 적용
(?imx)pattern    // 여러 플래그를 동시에


7) 유니코드/문자속성

  • 많은 엔진(PCRE, Java, JS with /u 등)은 \p{...}로 문자 속성 사용 가능:

    • \p{L} : 모든 문자(letters)

    • \p{N} : 숫자

    • \p{Han} 등 언어별 스크립트

  • 일부 엔진은 표준 \p를 지원하지 않으니(예: 표준 Python re는 미지원) 사용 전 엔진 문서 확인 필요.


8) 자주 쓰이는 실전 패턴들 (간단 & 실용)

  • 이메일(간단 검증. 완전한 RFC 검증은 복잡):

^[^\s@]+@[^\s@]+\.[^\s@]+$

  • IPv4 주소:

^(?:(?:25[0-5]|2[0-4]\d|1?\d{1,2})\.){3}(?:25[0-5]|2[0-4]\d|1?\d{1,2})$

  • 24시간 시:분 (HH:MM):

^(?:[01]\d|2[0-3]):[0-5]\d$

  • 날짜(YYYY-MM-DD, 기본 검증 — 윤년/월별 일수는 추가처리 필요):

^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$

  • 16진 색상 (#RRGGBB 또는 #RGB):

^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$

  • UUID (v1-v5 일반형):

^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89ABab][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$

  • 비밀번호 복잡도 예 (최소 8자, 대문자·소문자·숫자·특수문자 포함):

^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[^\w\s]).{8,}$

  • 숫자(정수/소수, 음수 허용):

^-?\d+(?:\.\d+)?$

  • URL(간단 검증):

^(https?:\/\/)?([\w\-]+\.)+[\w\-]+(\/[\w\-./?%&=]*)?$

(실전에서는 URL 파서/라이브러리 사용 권장)

  • HTML 태그 제거(매칭용, 파싱은 라이브러리 권장):

<[^>]+>

(주의: HTML 구조를 완벽히 다루진 못함)


9) 캡처 그룹/백레퍼런스 예시

(\w+)\s+\1

  • 같은 단어가 연속으로 오는 경우(예: “hello hello”)를 찾음. \1은 1번째 캡처 그룹을 재참조.

이름 있는 그룹 예:

(?<word>\w+)\s+(?P=word)   // PCRE/JS + Python 방식 혼용 예시 — 엔진별 문법 확인


10) 성능·안전: ReDoS(정규표현식 DoS)와 회피법

  • 문제 원인: 과도한 백트래킹을 일으키는 패턴(특히 중첩된 반복 (.+)+, (a|aa)+b 등)이 긴 입력에 대해 매우 느려짐.

  • 회피법:

    • 가능한 한 구체적인 문자 클래스를 사용(예: \d 대신 [0-9]는 같지만 명확성 유지).

    • 탐욕적 패턴을 최소화하고, 필요하면 소유적( possessive ) 또는 atomic 그룹 (?>...) 사용(PCRE/Java).

    • 비캡처 그룹 (?:...) 사용으로 캡처 비용 최소화.

    • 복잡한 구조(HTML, CSV 등)는 정규표현식이 아닌 전용 파서 사용.

    • 사용자 입력 길이 제한 및 타임아웃(엔진/라이브러리 제공 시).

예 — atomic group (PCRE/Java):

(?>a+)+b   // 백트래킹 차단


11) 엔진별 실무 팁

  • JavaScript: 문자열 리터럴에선 /pattern/flags. ES2018 이후 named groups · lookbehind 일부 지원(환경 확인). 글로벌(전역) 검색 시 /g 사용.

  • Python (re): r'pattern'(raw string) 권장. re.X로 가독성 향상, re.UNICODE는 기본(파이썬3). 이름 그룹은 (?P<name>...) 사용. 표준 re는 \p{} 미지원(복잡한 유니코드 속성은 regex 모듈 사용).

  • PHP / PCRE: 구분자(/.../)와 플래그(/i, /m, /s 등)을 사용. PCRE는 풍부한 확장(atomic, possessive) 지원.

  • Java (java.util.regex): 문자열 내에서 \\ 이스케이프 주의(예: "\\d+"). Java는 possessive quantifier 지원(++, *+, ?+)하고 성능 측면에 강함.


12) 실전 권장 패턴·관행

  • 명확하게 앵커 사용: 전체 일치를 원하면 ^...$로 감싸기.

  • 불필요한 캡처 금지: 캡처가 필요 없으면 (?:...) 사용.

  • 가독성 위해 verbose 모드 활용: 복잡한 패턴은 주석과 공백을 허용하는 x 모드로 작성.

  • 테스트: 다양한 입력(경계 조건·악의적 입력)을 가지고 충분히 시험. regex101.com 같은 도구로 즉석 확인(엔진 선택 가능).

  • 파싱 작업은 파서 사용: HTML, XML, CSV같이 문법이 있는 데이터는 전용 파서 권장.


댓글