정규표현식 실전 패턴 — 매번 검색하는 것들 총정리
정규표현식은 매번 새롭다. 이메일 검증을 할 때도, URL을 파싱할 때도 매번 검색한다. 내가 자주 쓰는 패턴만 모아서 이 글에 정리했다. 이제부터는 이 글을 북마크하고 필요할 때 찾아쓰면 된다.
기본 패턴
이메일 주소
완벽한 RFC 5322 정규표현식은 너무 복잡하다. 실무에서는 대부분 이 정도면 충분하다.
^[^\s@]+@[^\s@]+\.[^\s@]+$
더 엄격하게 하려면:
^[a-zA-Z0-9._%-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
하지만 이것도 완벽하지 않다. 실제로는 정규표현식보다 확인 이메일을 보내는 것이 더 안전하다.
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
console.log(emailRegex.test('user@example.com')); // true
console.log(emailRegex.test('invalid.email')); // false
URL
^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$
또는 더 간단하게:
^https?:\/\/.+$
전화번호 (한국)
^01[0-9]-?\d{3,4}-?\d{4}$
이 패턴은 010-1234-5678, 01012345678 등을 모두 허용한다.
const phoneRegex = /^01[0-9]-?\d{3,4}-?\d{4}$/;
console.log(phoneRegex.test('010-1234-5678')); // true
console.log(phoneRegex.test('01012345678')); // true
IP 주소 (IPv4)
^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
이 패턴은 0-255 범위의 4개 옥텟을 검증한다.
const ipRegex = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
console.log(ipRegex.test('192.168.1.1')); // true
console.log(ipRegex.test('256.1.1.1')); // false
로그 파싱
타임스탐프 파싱
흔한 로그 포맷 (2026-02-26 14:30:45):
^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
또는 구조화된 파싱을 위해 그룹을 사용:
^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})
const logLine = '2026-02-26 14:30:45 [ERROR] Connection failed';
const regex = /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}) \[(\w+)\] (.+)$/;
const match = logLine.match(regex);
if (match) {
const [, year, month, day, hour, minute, second, level, message] = match;
console.log({ year, month, day, hour, minute, second, level, message });
}
로그 레벨 추출
\[(ERROR|WARN|INFO|DEBUG)\]
고급 패턴
Lookahead와 Lookbehind
Lookahead는 특정 문자 앞에 있는 것을 찾는다.
\w+(?=@) // @앞의 모든 단어 문자
const email = 'user@example.com';
const username = email.match(/\w+(?=@)/)[0];
console.log(username); // 'user'
Lookbehind는 특정 문자 뒤에 있는 것을 찾는다. (모던 JavaScript에서 지원)
(?<=@)\w+ // @뒤의 모든 단어 문자
const email = 'user@example.com';
const domain = email.match(/(?<=@)[\w.]+/)[0];
console.log(domain); // 'example.com'
Named Groups (명명된 그룹)
정규표현식이 복잡해지면 그룹을 이름으로 참조하는 것이 좋다.
const dateRegex = /(?\d{4})-(?\d{2})-(?\d{2})/;
const match = '2026-02-26'.match(dateRegex);
console.log(match.groups.year); // '2026'
console.log(match.groups.month); // '02'
console.log(match.groups.day); // '26'
Non-greedy 매칭
기본적으로 정규표현식은 greedy하다. 즉, 가능한 한 많이 매칭한다.
const text = 'Hello
World
';
// Greedy (잘못된 결과)
const greedy = text.match(/.*<\/p>/);
console.log(greedy[0]); // '
Hello
World
'
// Non-greedy (올바른 결과)
const nonGreedy = text.match(/.*?<\/p>/g);
console.log(nonGreedy); // ['
Hello
', 'World
']
*?, +?, ?? 등을 사용해서 non-greedy 매칭을 한다.
일반적인 실수
Catastrophic Backtracking
복잡한 정규표현식은 매우 느릴 수 있다. 특히 텍스트가 패턴과 거의 맞지만 마지막에 실패하는 경우가 문제다.
// ❌ 위험: 백트래킹이 매우 많다
(a+)+b
// 이 텍스트는 프로세스를 한없이 계속할 것이다
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaac
// 직접 테스트하지 말 것! 브라우저가 멈칠 수 있다.
// const regex = /(a+)+b/;
// const text = 'a'.repeat(30) + 'c';
// regex.test(text); // 매우 오래 걸림
이를 피하려면 중첩된 quantifier를 피해야 한다.
// ✅ 안전한 버전
a+b
성능 최적화 팁
- Anchors를 사용하자 (^ 와 $)
- 구체적인 패턴을 먼저 작성하자
- character class를 사용하자 ([a-z] vs a|b|c)
- 불필요한 그룹을 피하자
실무 활용 팁
입력 검증
const validators = {
email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
phone: /^01[0-9]-?\d{3,4}-?\d{4}$/,
url: /^https?:\/\/.+$/,
ipv4: /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
username: /^[a-zA-Z0-9_]{3,20}$/
};
function validate(field, value) {
return validators[field].test(value);
}
console.log(validate('email', 'user@example.com')); // true
console.log(validate('phone', '01012345678')); // true
문자열 변환
// camelCase를 snake_case로
const camelCase = 'getUserData';
const snakeCase = camelCase.replace(/([A-Z])/g, '_$1').toLowerCase();
console.log(snakeCase); // 'get_user_data'
// 연속된 공백 제거
const text = 'Hello world';
const cleaned = text.replace(/\s+/g, ' ');
console.log(cleaned); // 'Hello world'
// URL에서 쿼리 파라미터 추출
const url = 'https://example.com?name=John&age=30';
const params = {};
url.replace(/[?&]([^=]+)=([^&]*)/g, (match, key, value) => {
params[key] = value;
});
console.log(params); // { name: 'John', age: '30' }
정규표현식 체크리스트
| 패턴 | 용도 | 정규표현식 |
|---|---|---|
| 이메일 | 기본 검증 | ^[^\s@]+@[^\s@]+\.[^\s@]+$ |
| URL | URL 검증 | ^https?:\/\/.+$ |
| 한국 전화번호 | 전화번호 | ^01[0-9]-?\d{3,4}-?\d{4}$ |
| IPv4 | IP 주소 | ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ |
| 타임스탐프 | 로그 파싱 | ^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$ |
정규표현식은 강력하지만 복잡할 수 있다. 이 글의 패턴들을 기억하고, 더 복잡한 경우에는 정규표현식 테스터(regex101.com 등)를 사용하자. 그리고 항상 성능을 고려하자.