WeniVooks

검색

정규표현식 톺아보기 with JavaScript and Python

고급 패턴과 특수 문자

1. 게으른 수량자

물음표는 없을 수도 있다는 의미입니다. 기본 수량자는 "탐욕적"(greedy)으로 동작하여 가능한 많은 문자를 매칭하려 합니다. 수량자 뒤에 ?를 붙이면 없을 수도 있기 때문에 "게으른"(lazy)으로 표현합니다. Lazy Quantifier라고 불립니다.

010[- .]?\d{4}[- .]?\d{4}    // 전화번호 패턴
010[- .]?\d{4}[- .]?\d{4}    // 전화번호 패턴

이렇게 실습을 먼저 진행해보겠습니다. 물음표는 없을 수도 있기 때문에 아래와 같은 패턴도 매칭됩니다.

01012345678
01012345678
1.1 탐욕적 vs 게으른 매칭
// 탐욕적 매칭
/h.*o/gm    // "hello world hello" -> "hello world hello"
 
// 게으른 매칭
/h.*?o/gm   // "hello world hello" -> "hello", "hello"
// 탐욕적 매칭
/h.*o/gm    // "hello world hello" -> "hello world hello"
 
// 게으른 매칭
/h.*?o/gm   // "hello world hello" -> "hello", "hello"
1.2 모든 게으른 수량자
*?    // 0회 이상 (최소한으로 매칭)
+?    // 1회 이상 (최소한으로 매칭)
??    // 0회 또는 1회 (최소한으로 매칭)
{n}?  // 정확히 n회 (의미 없음)
{n,}? // 최소 n회 (최소한으로 매칭)
{n,m}?// n회 이상 m회 이하 (최소한으로 매칭)
*?    // 0회 이상 (최소한으로 매칭)
+?    // 1회 이상 (최소한으로 매칭)
??    // 0회 또는 1회 (최소한으로 매칭)
{n}?  // 정확히 n회 (의미 없음)
{n,}? // 최소 n회 (최소한으로 매칭)
{n,m}?// n회 이상 m회 이하 (최소한으로 매칭)

2. 전방탐색과 후방탐색

2.1 전방탐색

전방탐색(Lookahead)은 특정 패턴 뒤에 다른 패턴이 오는지 확인하되, 해당 패턴은 매칭에 포함하지 않습니다.

// 긍정 전방탐색 (?=) - 뒤에 특정 패턴이 있는 경우
/\w+(?=@)/gm   // 이메일에서 @ 앞부분만 매칭
 
// 부정 전방탐색 (?!) - 뒤에 특정 패턴이 없는 경우
/\d+(?!\.)/gm  // 뒤에 점이 오지 않는 숫자들
// 긍정 전방탐색 (?=) - 뒤에 특정 패턴이 있는 경우
/\w+(?=@)/gm   // 이메일에서 @ 앞부분만 매칭
 
// 부정 전방탐색 (?!) - 뒤에 특정 패턴이 없는 경우
/\d+(?!\.)/gm  // 뒤에 점이 오지 않는 숫자들

아래와 같이 활용할 수 있습니다.

// 링크 텍스트만 추출
/\[.*?(?=\])/gm    // [링크](http://...) -> "링크" 부분만 추출
 
// 파일명만 추출 (확장자 제외)
/\w+(?=\.txt)/gm   // file.txt -> "file"
// 링크 텍스트만 추출
/\[.*?(?=\])/gm    // [링크](http://...) -> "링크" 부분만 추출
 
// 파일명만 추출 (확장자 제외)
/\w+(?=\.txt)/gm   // file.txt -> "file"
2.2 후방탐색

후방탐색(Lookbehind)은 특정 패턴 앞에 다른 패턴이 있는지 확인하되, 해당 패턴은 매칭에 포함하지 않습니다.

// 긍정 후방탐색 (?<=) - 앞에 특정 패턴이 있는 경우
/(?<=\$)\d+/gm    // 달러 기호 뒤의 숫자만 매칭
 
// 부정 후방탐색 (?<!) - 앞에 특정 패턴이 없는 경우
/(?<!-)\d+/gm     // 하이픈 앞에 없는 숫자들
// 긍정 후방탐색 (?<=) - 앞에 특정 패턴이 있는 경우
/(?<=\$)\d+/gm    // 달러 기호 뒤의 숫자만 매칭
 
// 부정 후방탐색 (?<!) - 앞에 특정 패턴이 없는 경우
/(?<!-)\d+/gm     // 하이픈 앞에 없는 숫자들

아래와 같이 활용할 수 있습니다.

// 통화 금액에서 숫자만 추출
/(?<=\$)\d+(\.\d{2})?/gm    // $12.34 -> "12.34"
 
// 도메인에서 최상위 도메인 추출
/(?<=\.)[a-z]+$/gm          // example.com -> "com"
 
// 특정 접두사가 없는 단어 찾기
/(?<!re)\w+/gm              // reload -> "load"
// 통화 금액에서 숫자만 추출
/(?<=\$)\d+(\.\d{2})?/gm    // $12.34 -> "12.34"
 
// 도메인에서 최상위 도메인 추출
/(?<=\.)[a-z]+$/gm          // example.com -> "com"
 
// 특정 접두사가 없는 단어 찾기
/(?<!re)\w+/gm              // reload -> "load"

3. 특수 문자열 패턴

3.1 단어 경계

단어의 경계를 나타내는 특수 문자입니다.

/\bword\b/gm    // "word"는 매칭, "words"는 매칭 안됨
/\bhello\b/gm   // 독립된 "hello" 단어만 매칭
/\bword\b/gm    // "word"는 매칭, "words"는 매칭 안됨
/\bhello\b/gm   // 독립된 "hello" 단어만 매칭

아래와 같이 활용할 수 있습니다.

// 완전한 단어 찾기
/\bcat\b/gm     // "cat" 매칭, "category" 매칭 안됨
 
// 특정 접두사로 시작하는 단어
/\bre\w+/gm     // "reload", "rewrite" 등
 
// 특정 접미사로 끝나는 단어
/\w+ing\b/gm    // "loading", "writing" 등
// 완전한 단어 찾기
/\bcat\b/gm     // "cat" 매칭, "category" 매칭 안됨
 
// 특정 접두사로 시작하는 단어
/\bre\w+/gm     // "reload", "rewrite" 등
 
// 특정 접미사로 끝나는 단어
/\w+ing\b/gm    // "loading", "writing" 등
3.2 줄의 시작과 끝

이미 배웠지만, 멀티라인 모드에서의 동작을 자세히 살펴봅니다.

// 줄의 시작 ^
/^hello/gm      // 각 줄의 시작에 있는 "hello"
 
// 줄의 끝 $
/world$/gm      // 각 줄의 끝에 있는 "world"
 
// 전체 문자열의 시작과 끝
/^hello.*world$/gm    // "hello"로 시작하고 "world"로 끝나는 한 줄
// 줄의 시작 ^
/^hello/gm      // 각 줄의 시작에 있는 "hello"
 
// 줄의 끝 $
/world$/gm      // 각 줄의 끝에 있는 "world"
 
// 전체 문자열의 시작과 끝
/^hello.*world$/gm    // "hello"로 시작하고 "world"로 끝나는 한 줄

4. 연습 예제

4.1 문제
  1. HTML 태그 내의 내용만 추출하는 패턴을 만드세요.
  2. 이메일 주소에서 도메인 부분만 추출하는 패턴을 만드세요.
  3. 금액 표시에서 통화 기호를 제외한 숫자만 추출하는 패턴을 만드세요.
  4. 독립된 숫자 단어만 찾는 패턴을 만드세요.
  5. URL에서 프로토콜을 제외한 도메인만 추출하는 패턴을 만드세요.
4.2 해답
  1. /<.*?>(.*?)<\/.*?>/gm
  2. /(?<=@)[\w.-]+/gm
  3. /(?<=\$)\d+(\.\d{2})?/gm
  4. /\b\d+\b/gm
  5. /(?<=:\/\/)([^\/]+)/gm

⚠️ 실습 시 주의사항

  • 전방/후방 탐색은 매칭 결과에 포함되지 않습니다.
  • 게으른 수량자는 필요한 최소한의 문자만 매칭합니다.
  • 단어 경계는 공백, 문장 부호 등과 구분됩니다.
  • 전방/후방 탐색의 패턴이 복잡해질수록 성능에 영향을 줄 수 있습니다.
1.3 패턴의 반복과 그룹화2장 프로그래밍 언어의 정규표현식