[Javascript] Regular Expression
JS regex, JS RegExp, 정규식 JavaScript
정의
JavaScript 의 정규식. RegExp 객체 또는 리터럴 /.../ 로 표현. ECMAScript 정규식 문법 (Perl 의 부분집합).
생성
const re = /pattern/flags;
const re = new RegExp('pattern', 'flags');
const re = new RegExp(pattern); // pattern 이 string 또는 RegExp
리터럴이 가독성 좋음. 동적 패턴은 new RegExp.
flags
| flag | 의미 |
|---|---|
g | global (모든 매치) |
i | case-insensitive |
m | multiline (^ $ 가 각 줄에) |
s | dotAll (. 가 \n 포함) |
u | unicode (Unicode 코드 포인트) |
y | sticky (lastIndex 부터 매칭) |
d | indices (group 의 시작/끝 위치) |
/python/gi // global + case-insensitive
자주 쓰는 메서드
| 메서드 | 의미 |
|---|---|
regex.test(str) | true/false |
regex.exec(str) | match 객체 또는 null |
str.match(regex) | g 면 배열, 아니면 exec 같음 |
str.matchAll(regex) | iterator (g 필수) |
str.search(regex) | 첫 위치 (없으면 -1) |
str.replace(regex, repl) | 치환 |
str.replaceAll(regex, repl) | g flag 필수 |
str.split(regex) | 분할 |
/\d+/.test('abc 123') // true
'abc 123'.match(/\d+/) // ['123', index: 4, ...]
'abc 123 456'.match(/\d+/g) // ['123', '456']
'hello'.replace(/l/g, 'L') // 'heLLo'
자주 쓰는 패턴 cheatsheet
| 패턴 | 의미 |
|---|---|
. | 임의 문자 (개행 제외) |
\d, \D | 숫자, 비숫자 |
\w, \W | 영숫자_, 그 외 |
\s, \S | 공백, 비공백 |
^, $ | 문자열 시작, 끝 |
\b, \B | 단어 경계, 비경계 |
* | 0+ |
+ | 1+ |
? | 0 또는 1 |
{n}, {n,m} | 정확/범위 |
[abc] | 집합 |
[^abc] | 부정 집합 |
[a-z] | 범위 |
| | OR |
() | 캡처 그룹 |
(?:...) | 비캡처 |
(?<name>...) | named group |
(?=...) | lookahead |
(?!...) | negative lookahead |
(?<=...) | lookbehind |
(?<!...) | negative lookbehind |
캡처 그룹
const m = '2024-01-15'.match(/(\d{4})-(\d{2})-(\d{2})/);
// m[0] = '2024-01-15' (전체)
// m[1] = '2024' (1번 그룹)
// m[2] = '01'
// m[3] = '15'
// named
const m2 = '2024-01-15'.match(/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/);
m2.groups.y; // '2024'
치환
'foo bar'.replace(/(\w+) (\w+)/, '$2 $1'); // 'bar foo'
'2024-01-15'.replace(/(\d+)-(\d+)-(\d+)/, '$3/$2/$1'); // '15/01/2024'
// named
'2024-01-15'.replace(/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/, '$<d>/$<m>/$<y>');
// 함수 replacer
'abc'.replace(/./g, (ch) => ch.toUpperCase()); // 'ABC'
// 함수 + 그룹
'2024-01-15'.replace(/(\d+)/g, (n) => n.padStart(4, '0'));
lookahead / lookbehind
// 다음에 'USD' 가 오는 숫자만
'100 USD, 200 EUR'.match(/\d+(?= USD)/g); // ['100']
// 이전이 '$' 인 숫자
'$100 €200'.match(/(?<=\$)\d+/g); // ['100']
// 다음에 'px' 가 아닌 숫자
'10em 20px 30em'.match(/\d+(?!px)/g);
test vs match vs matchAll
// 존재 검사만
/\d+/.test('abc 123') // true (빠름)
// 첫 매치
'abc 123 456'.match(/\d+/)
// ['123', index: 4, input: 'abc 123 456']
// 모든 매치 (배열)
'abc 123 456'.match(/\d+/g)
// ['123', '456']
// 모든 매치 + 그룹 (iterator)
for (const m of 'abc 123 456'.matchAll(/(\d+)/g)) {
console.log(m[0], m[1], m.index);
}
matchAll 가 가장 정보 풍부.
자주 만나는 패턴
email (대략)
/^[\w.+-]+@[\w-]+\.[\w.-]+$/
완벽한 email 정규식은 매우 복잡 (RFC 5322). 보통 위 정도로 충분.
URL
/^https?:\/\/[\w.-]+(:\d+)?(\/.*)?$/
전화번호 (한국)
/^0\d{1,2}-\d{3,4}-\d{4}$/
화이트스페이스 정규화
str.replace(/\s+/g, ' ').trim()
함정
1. lastIndex (g flag)
const re = /\d+/g;
re.exec('abc 123 456'); // ['123', index: 4]
re.exec('abc 123 456'); // ['456', index: 8]
re.exec('abc 123 456'); // null
re.exec('abc 123 456'); // ['123', ...] (재시작)
g flag 의 lastIndex 가 상태. 같은 regex 객체 공유 시 함정.
2. metachar escape
'a.b.c'.split('.') // ['a', 'b', 'c']
'a.b.c'.split(/\./) // ['a', 'b', 'c']
'a.b.c'.split(/./) // ['', '', '', '', ''] ⚠️ . 은 any
3. 동적 패턴의 escape
function escapeRegex(s) {
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
new RegExp(escapeRegex(userInput))
사용자 입력을 정규식으로 만들 때 escape 필수.
4. 욕심쟁이 vs 게으른
'<a><b>'.match(/<.+>/)[0] // '<a><b>' (욕심)
'<a><b>'.match(/<.+?>/)[0] // '<a>' (게으른)
💬 댓글