/ /

치트시트 — 클릭하여 삽입

정규표현식이란?

정규표현식(regex 또는 regexp)은 검색 패턴을 정의하는 문자 시퀀스입니다. 문자열 검색, 유효성 검사, 텍스트 추출 및 치환에 사용됩니다. Regex는 거의 모든 프로그래밍 언어에서 지원되며 텍스트 처리 작업을 하는 모든 개발자에게 필수적인 도구입니다.

Regex 구문 빠른 참조

  • . — 줄바꿈을 제외한 모든 문자와 일치
  • ^ / $ — 문자열(또는 멀티라인 모드에서 줄)의 시작 / 끝
  • * / + / ? — 0개 이상 / 1개 이상 / 0개 또는 1개
  • {n,m} — n개에서 m개 사이의 반복
  • [abc] — 문자 클래스 — a, b 또는 c와 일치
  • [^abc] — 부정 문자 클래스
  • (abc) — 캡처 그룹
  • (?:abc) — 비캡처 그룹
  • \d / \w / \s — 숫자 / 단어 문자 / 공백
  • a|b — 선택 — a 또는 b와 일치

일반적인 Regex 패턴

  • 이메일: [\w.+-]+@[\w-]+\.[a-zA-Z]{2,}
  • URL: https?://[\w\-._~:/?#[\]@!$&'()*+,;=%]+
  • IPv4: (\d{1,3}\.){3}\d{1,3}
  • 전화번호 (미국): (\+1\s?)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}
  • Hex 색상: #([a-fA-F0-9]{6}|[a-fA-F0-9]{3})
  • 날짜 (YYYY-MM-DD): \d{4}-\d{2}-\d{2}

정규식 마스터하기: 모든 개발자가 알아야 할 패턴

정규식은 개발자 도구 중 가장 강력한 도구 중 하나이지만, 가장 오해받기도 합니다. 효과적인 정규식을 작성하는 핵심은 기본 구성 요소를 이해하고 복잡한 패턴을 처음부터 작성하려 하지 않고 체계적으로 조합하는 것입니다.

일반적인 작업에 필수적인 정규식 패턴

  • 이메일 검증: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ — 유효한 이메일 형식의 99%를 커버합니다. 프로덕션에서는 정규식만 사용하지 말고 언어의 내장 이메일 검증기 사용을 고려하세요.
  • URL 매칭: https?://[^\s/$.?#].[^\s]* — HTTP와 HTTPS URL을 매칭합니다. 텍스트에서 링크를 추출하는 데 간단하지만 효과적입니다.
  • IPv4 주소: \b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b — IP 주소 형식을 매칭합니다. 범위 검증은 수행하지 않습니다.
  • 날짜 형식 (YYYY-MM-DD): \d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]) — 기본 월/일 검증이 포함된 ISO 8601 날짜 형식을 매칭합니다.
  • 비밀번호 강도: ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$ — 대문자, 소문자, 숫자, 특수문자를 포함한 8자 이상이 필요합니다.

정규식 성능: 재앙적 백트래킹 피하기

재앙적 백트래킹은 정규식 엔진이 특정 입력에 대해 기하급수적으로 많은 조합을 시도하며 멈추는 현상입니다. 이로 인해 애플리케이션이 멈추거나 ReDoS(정규식 서비스 거부) 공격이 가능해집니다.

  • 위험한 패턴: (a+)+$ — 입력 "aaaaaaaaaaaaaaaaab"에 대해, 엔진이 내부와 외부 그룹 간에 a를 나누는 모든 가능한 방법을 시도하므로 기하급수적 시간이 소요됩니다.
  • 안전한 대안: a+$ — 가능하면 중첩된 수량자를 평탄화합니다.
  • 경험 법칙: 수량자 중첩((x+)+, (x*)*, (x+)*)은 내부 패턴이 외부 반복과 같은 문자를 매칭할 수 없다고 확신하지 않는 한 피하세요.

프로덕션 애플리케이션에서는 항상 정규식 작업에 타임아웃을 설정하고, 선형 시간 매칭을 지원하는 정규식 라이브러리(Go의 RE2나 Rust의 rust-regex 등) 사용을 고려하세요.

정규식 종류: 언어별 주요 차이점

모든 정규식 엔진이 같지는 않습니다. 중요한 차이점은 다음과 같습니다:

  • JavaScript: ES2018까지 룩비하인드 미지원. /pattern/flags 구문 사용. g 플래그는 lastIndex로 상태 유지.
  • Python: re 모듈 사용. (?P<name>...) 구문으로 명명된 그룹 지원.
  • Go: RE2 엔진 사용 — 백트래킹 없음, 선형 시간 보장, 단 전방탐색/후방탐색 미지원.
  • Java: 소유 수량자(a++)와 원자 그룹을 포함한 완전한 PCRE 유사 지원.

정규표현식에 대한 자주 묻는 질문

정규표현식에서 .*와 .+의 차이점은 무엇인가요?

별표(*)는 앞의 요소가 "0개 이상"을 의미하고, 더하기(+)는 "1개 이상"을 의미합니다. 패턴 .*는 빈 문자열을 포함한 모든 문자열과 일치하며, .+는 최소 하나의 문자가 필요합니다. 둘 다 기본적으로 탐욕적(greedy)으로 가능한 많이 매치합니다. ?를 추가하면 게으른(lazy) 매칭이 됩니다(가능한 적게 매치): .*?.+?.

정규표현식 플래그 g, i, m, s는 무엇을 하나요?

g(global) 플래그는 첫 번째에서 멈추지 않고 모든 매치를 찾습니다. i 플래그는 대소문자를 무시합니다. m(multiline) 플래그는 ^$가 전체 문자열이 아닌 각 줄의 시작과 끝과 일치하게 합니다. s(dotAll) 플래그는 점이 줄바꿈 문자도 일치하게 합니다. 필요에 따라 플래그를 결합하세요: /pattern/gim.

리터럴 점, 괄호 또는 기타 특수 문자를 어떻게 매칭하나요?

백슬래시로 특수 regex 문자를 이스케이프합니다. 리터럴 점은 .입니다 (백슬래시 없이 점은 모든 문자와 일치합니다). 리터럴 괄호는 ()입니다. 이스케이프가 필요한 다른 문자: ^ $ | ? * + { } [ ]. 예를 들어 URL example.com을 그대로 매칭하려면 /example.com/으로 작성하세요 — 그렇지 않으면 점이 모든 문자와 일치합니다.

탐욕적(greedy) 수량자와 게으른(lazy) 수량자의 차이점은 무엇인가요?

탐욕적 수량자(*, +, {n,m})는 전체 패턴이 여전히 일치하면서 가능한 많이 매치하려고 합니다. 게으른(비탐욕적) 수량자(*?, +?, {n,m}?)는 가능한 적게 매치합니다. 예를 들어 <b>bold</b>에서 탐욕적 /<.*>/는 전체 문자열과 일치하지만, 게으른 /<.*?>/<b>만 일치합니다.

관련 개발자 도구