BioPlayground

🧬
목록으로

정규식 — 두려움 없이 패턴 매칭하기

정규식이 왜 어려워 보이는지, 핵심 문법만 익히면 어떻게 쓸 수 있는지, 실무 패턴과 함께 설명합니다.

중급
|
5
|
검증 완료 (2026-07)
진행률0/20 (0%)

정규식 — 두려움 없이 패턴 매칭하기

이 토픽을 마치면

정규식의 기본 문법을 읽을 수 있고, 이메일·전화번호·날짜 같은 패턴을 직접 작성하며, "이 정규식이 뭘 하는 건지" 해석할 수 있습니다.


왜 무섭게 생겼을까

회원가입 폼에서 이메일 형식을 검증해야 합니다. if문으로 하면:

javascript
function isEmail(str) {
  if (!str.includes("@")) return false;
  const parts = str.split("@");
  if (parts.length !== 2) return false;
  if (parts[0].length === 0) return false;
  if (!parts[1].includes(".")) return false;
  // ... 더 있음
}

정규식으로 하면 한 줄:

javascript
const isEmail = str => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(str);

짧아진 대신 읽기 어려워졌습니다. 정규식이 무서운 이유는 압축된 문법 때문입니다. 하지만 기호 몇 개만 익히면 대부분의 패턴을 읽고 쓸 수 있습니다.


5분이면 되는 핵심 문법

text
.       아무 문자 1개
\d      숫자 (0-9)
\w      단어 문자 (a-z, A-Z, 0-9, _)
\s      공백 (스페이스, 탭, 줄바꿈)
[abc]   a 또는 b 또는 c
[^abc]  a, b, c가 아닌 것

횟수:

text
*       0번 이상 (없어도 됨)
+       1번 이상 (최소 1개)
?       0번 또는 1번 (있어도 되고 없어도 됨)
{3}     정확히 3번
{2,5}   2~5번

위치:

text
^       문자열의 시작
$       문자열의 끝

이게 전부입니다. 이 기호들의 조합으로 거의 모든 패턴을 표현합니다.


실전 패턴 5가지

1. 전화번호 (010-1234-5678)

javascript
const phoneRegex = /^010-\d{4}-\d{4}$/;
phoneRegex.test("010-1234-5678");  // true
phoneRegex.test("02-123-4567");    // false

\d{4}는 "숫자 4개"입니다.

2. 비밀번호 (8자 이상, 숫자 포함)

javascript
const pwRegex = /^(?=.*\d).{8,}$/;
pwRegex.test("hello123");   // true
pwRegex.test("helloworld"); // false (숫자 없음)
pwRegex.test("hi1");        // false (8자 미만)

(?=.*\d)전방탐색입니다. "어딘가에 숫자가 있는지" 확인만 하고 실제로 소비하지 않습니다.

3. HTML 태그 제거

javascript
const stripped = "<b>안녕</b>하세요".replace(/<[^>]+>/g, "");
// "안녕하세요"

<[^>]+>는 "< 로 시작하고, > 가 아닌 문자가 1개 이상, > 로 끝나는 것"입니다.

4. 날짜 추출 (YYYY-MM-DD)

python
import re
text = "회의는 2026-07-05에 예정입니다. 마감은 2026-08-01."
dates = re.findall(r'\d{4}-\d{2}-\d{2}', text)
# ['2026-07-05', '2026-08-01']

5. 캡처 그룹 — 부분 추출

python
import re
match = re.search(r'(\d{4})-(\d{2})-(\d{2})', "오늘은 2026-07-05입니다")
year, month, day = match.group(1), match.group(2), match.group(3)
# '2026', '07', '05'

소괄호 ()로 감싼 부분이 그룹입니다. group(1), group(2)로 각각 꺼낼 수 있습니다.


정규식 읽는 법

text
/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/

이걸 해석해봅시다:

text
^                       문자열 시작
[A-Za-z0-9._%+-]+       영문/숫자/특수문자 1개 이상 (로컬 파트)
@                       골뱅이
[A-Za-z0-9.-]+          영문/숫자/점/하이픈 1개 이상 (도메인)
\.                      점 (이스케이프)
[A-Za-z]{2,}            영문 2자 이상 (TLD: com, kr, ...)
$                       문자열 끝

왼쪽에서 오른쪽으로, 한 토큰씩 읽으면 됩니다.


흔한 실수

javascript
// ❌ 탐욕적 매칭 — 가장 긴 것을 잡음
"<b>볼드</b>와 <i>이탤릭</i>".match(/<.+>/);
// "<b>볼드</b>와 <i>이탤릭</i>" — 전부 매칭됨

// ✅ 비탐욕적 매칭 — 가장 짧은 것을 잡음
"<b>볼드</b>와 <i>이탤릭</i>".match(/<.+?>/);
// "<b>" — 첫 태그만 매칭

// ✅ 또는 부정 문자 클래스
"<b>볼드</b>와 <i>이탤릭</i>".match(/<[^>]+>/);
// "<b>"

+*는 기본적으로 탐욕적(greedy)입니다. 최대한 많이 잡으려 합니다. ?를 붙이면 비탐욕적(lazy)으로 바뀌어 최소한만 잡습니다.


정규식은 만능이 아니다

정규식으로 하면 안 되는 것:

  • HTML/XML 파싱: 중첩 태그는 정규식으로 정확히 처리 불가. DOM 파서를 쓰세요.
  • 복잡한 문법 검증: JSON, 프로그래밍 언어 구문 등은 파서가 필요합니다.
  • 성능이 중요한 대량 처리: ReDoS(정규식 서비스 거부) 취약점에 주의.

정규식은 "패턴이 간단하고, 입력이 한 줄짜리"일 때 가장 강력합니다.


핵심 한 줄: 정규식은 \d(숫자), +(1개 이상), [](문자 클래스) 세 가지만 알면 실무 패턴의 80%를 커버합니다. 무섭게 생겼지만 왼쪽에서 오른쪽으로 한 토큰씩 읽으면 됩니다.