정규표현식이란?
정규표현식은 문자열에서 특정 내용을 찾거나 대체 또는 발췌하는데 사용되는 표현식입니다. 정규식이라고도 하며, 대표적인 사용 예로 input
에 전화번호나 이메일을 입력했을때 옳지 않은 값을 정규표현식으로 필터링하여 경고창을 띄우는 방식으로 자주 사용됩니다.
만약 정규표현식을 사용하지 않는다면, 입력된 데이터의 필터링을 위해 반복문과 조건문을 사용하여 복잡한 코드를 작성해야 하는데, 정규표현식을 사용하면 복잡한 필터링을 위한 코드도 매우 간단하게 표현할 수 있습니다. 정규표현식을 유용하게 사용할 수 있는 대표적인 상황은 다음과 같습니다.
- 각각 다른 포맷으로 저장된 수많은 전화번호 데이터를 추출하는 경우
- 사용자가 입력한 이메일, 휴대폰 번호, IP 주소 등을 검증하는 경우
- 코드에서 특정 변수의 이름을 치환하면서, 해당 변수의 이름을 포함하는 함수를 제외하는 경우
- 특정 조건과 위치에 따라 문자열에 포함된 공백이나 특수문자를 제거해야 하는 경우
이 외에도 정규표현식은 다양한 상황에서 활용할 수 있는 강력한 툴입니다. 하지만 정규표현식의 경우 문법에 주석이나 공백을 허용하지 않고, 여러가지 기호를 혼합하여 사용하기 때문에 코드의 가독성이 떨어집니다. 그래서 필터링 동작을 표현식으로 작성하는 것이 쉽지 않다는 단점도 있습니다.
// 휴대폰번호 양식 검사의 예 // \d는 숫자, {} 안의 숫자는 갯수를 의미 const regex = /\d{3}-\d{4}-\d{4}/; regex.test('010-0000-0000') // true; regex.test('01-00-00') // false;
정규표현식의 구조와 메서드
정규표현식의 구성 코드는 다음과 같이, 슬래시(/) 문자 두개 사이에 정규식 기호가 들어가는 형태로, 슬래시 문자 뒤의 i
는 정규식 플래그를 의미합니다.
// 리터럴 방식 const regex = /abc/; // 생성자 방식 // 아래의 두 가지 방법 모두 사용 가능 const regex = new RegExp("abc"); const regex = new RegExp(/abc/);
정규표현식 메서드
정규표현식으로 이메일이나 전화번호 등을 검사하고, 필터링하기 위해서는 정규식 메서드를 이용하여 패턴을 검사하고, 매칭되는 문자열을 추출하거나 변환해야 합니다. 다음은 자바스크립트에서 제공하는 정규식의 메서드들입니다.
메서드 | 의미 |
---|---|
“string”.match(/regex/)
|
“문자열”에서 “정규표현식”에 매칭되는 항목들을 배열로 반환
|
“string”.replace(/regex/, “대체문자열”)
|
“정규표현식”에 매칭되는 항목을 “대체문자열”로 변환
|
“string”.split(/regex/)
|
“문자열”을 “정규표현식”에 매칭되는 항목으로 쪼개어 배열로 반환
|
/regex/.test(“string”)
|
“문자열”이 “정규표현식”과 매칭되면
true , 아니면 false |
/regex/.exec(“string”)
|
match 메서드와 유사하지만, 무조건 첫번째 매칭 결과만 반환 |
const regex = /apple/; // "문자열"이 /regex/와 매칭되면 true, 아니면 false 반환 regex.test("Hello banana and apple"); // true // "문자열"에서 /regex/에 매칭되는 항목들을 배열로 반환 const txt = "Hello banana and apple"; txt.match(regex); // ['apple'] // "정규표현식"에 매칭되는 항목을 "대체문자열"로 변환 txt.replace(regex, "watermelon"); // 'Hello banana and watermelon'
정규식 플래그
정규식 플래그는 정규식을 생성할 때 고급 검색을 위한 전역 옵션을 설정하는 기능으로, 다음과 같은 옵션이 있습니다.
플래그 | 의미 | 설명 |
---|---|---|
i
|
Ignore Case
|
대소문자를 구별하지 않고 검색
|
g
|
Global
|
문자열 내의 모든 패턴을 검색
|
m
|
Multi Line
|
문자열의 행이 바뀌더라도 계속 검색
|
s
|
space
|
. (모든 문자를 뜻하는 정규식)에 개행 문자 \n 도 포함 |
u
|
unicode
|
유니코드 지원
|
y
|
sticky
|
문자 내 특정 위치에서 검색을 진행하는 ‘sticky’ 모드 활성화
|
전역 검색: g
만약 전역 검색 플래그가 없다면 최초의 검색 결과 하나만 반환하지만, 전역 검색 플래그가 있는 경우에는 모든 검색 결과를 배열로 반환합니다.
const str = "abcabc"; // 최초 발견된 문자만 반환 str.match(/a/); // ["a", index: 0, input: "abcabc", groups: undefined] // 모든 결과가 배열로 반환 str.match(/a/g); // (2) ["a", "a"]
줄바꿈 검색: m
여러 줄의 문자열에서 필터링을 하는 경우에 사용됩니다. 뒤에서 살펴 볼 입력 시작(^
) 앵커와 입력 종료($
) 앵커는 전체 문자열이 아닌 각 문자열 별로만 대응이 되는데, 만약 모든 문자열을 검색해야 하는 경우라면 m
플래그를 사용하면 됩니다.
const str = `Hello World and Power Hello? Power Overwhelming!!`; // Hello라는 단어로 시작하는지 검사 // ^는 문장 시작점을 의미 str.match(/^Hello/); // ["Hello"] // Power라는 단어로 시작하는지 검사 // 줄바꿈이 된 문자열에 있어 해당 단어는 검색 실패 str.match(/^Power/); // null // m 플래그를 추가하면 검색 성공 str.match(/^Power/m); // ['Power'] // 모든 문자열에서 검색해야 하는 경우, g 플래그도 추가 str.match(/^Power/gm); // ['Power', 'Power']
대소문자 구분 없음: i
정규식은 기본적으로 대소문자를 구분하는데, i
플래그를 추가하여 대소문자를 구분하지 않도록 설정할 수 있습니다.
const str = "abcABC"; // 대소문자 구분없이 'a'를 검색함 str.match(/a/gi); // (2) ["a", "A"]
정규식 패턴 기호들
특정 문자 및 숫자 매칭 패턴
정규식은 다음의 패턴을 사용하여 특정 문자나 숫자와 매칭하는 문자열을 찾을 수 있습니다.
패턴 | 의미 |
---|---|
a-zA-Z
|
영어알파벳(-으로 범위 지정)
|
ㄱ-ㅎ가-힣
|
한글 문자(-으로 범위 지정)
|
0-9
|
숫자(-으로 범위 지정)
|
.
|
모든 문자열(숫자, 한글, 영어, 특수기호, 공백 모두), 줄바꿈은 제외
|
\d
|
숫자
|
\D
|
숫자가 아닌 것
|
\w
|
밑줄 문자를 포함한 영어 및 숫자 문자에 대응
[A-Za-z0-9_] 와 동일함 |
\W
|
\w 가 아닌 것
|
\s
|
공백
|
\S
|
공백이 아닌 것
|
\특수기호
|
특수기호
\* , \^ , \& , \! , \? …등을 사용 |
\b
|
영문 대소문자 52개 + 숫자 10개 + _(underscore)의 63개 문자가 아닌 나머지 문자에 일치하는 경계(boundary)
|
\B
|
63개 문자에 일치하는 경계
|
\x
|
16진수 문자에 일치
/\x61/ 는 a에 일치함 |
\0
|
8진수 문자에 일치
/\141/ 은 a에 일치함 |
\u
|
유니코드(Unicode) 문자에 일치
/\u0061/ 는 a에 일치함 |
\c
|
제어(Control) 문자에 일치
|
\f
|
폼 피드(FF, U+000C) 문자에 일치
|
\n
|
줄 바꿈(LF, U+000A) 문자에 일치
|
\r
|
캐리지 리턴(CR, U+000D) 문자에 일치
|
\t
|
탭 (U+0009) 문자에 일치
|
정규식 검색 기준 패턴
정규식은 다음의 패턴을 사용하여 검색의 기준을 지정할 수 있습니다.
기호 | 의미 |
---|---|
|
|
OR(a|b)
|
[]
|
괄호안의 문자들 중 하나로, or의 처리 묶음
/abc/ : “abc”를 포함/[abc]/ : “a” 또는 “b” 또는 “c” 를 포함[다-바] : 다 or 라 or 마 or 바 |
[^문자]
|
괄호안의 문자를 제외한 것
[^lgEn] “l” “g” “E” “N” 4개 문자를 제외함대괄호 안에서 쓰면 제외의 뜻, 대괄호 밖에서 쓰면 시작점의 뜻으로 사용됨 |
^문자열
|
특정 문자열로 시작됨
/^www/ |
문자열$
|
특정 문자열로 끝남
/com$/ |
정규식 문자 반복 패턴
정규식은 다음의 패턴을 사용하여 문자의 반복 패턴을 검사할 수 있습니다.
기호 | 의미 |
---|---|
?
|
없거나 최대 한개 매칭
/apple?/ |
*
|
없거나 여러개 매칭
/apple*/ |
+
|
최소 한개이상 여러개의 문자 매칭
/apple+/ |
*?
|
없거나 있거나 and 없거나 최대 한개 매칭
{0} 와 동일함 |
+?
|
최소 한개 이상 and 없거나 최대 한개 문자 매칭
{1} 와 동일함 |
{n}
|
n개
|
{Min,}
|
최소 Min개 이상
|
{Min, Max}
|
최소 Min개 이상, 최대 Max개 이하
{3,5}? == {3} 와 동일함 |
정규식 그룹 패턴
정규식은 다음의 패턴을 사용해 그룹을 만들 수 있으며, 정규표현식 중에서도 상당히 난이도가 있는 패턴입니다.
기호 | 의미 |
---|---|
()
|
그룹화 및 캡쳐
|
(?: 패턴)
|
그룹화, 캡쳐 없음
|
(?=)
|
앞쪽 일치(Lookahead)
/ab(?=c)/ |
(?!)
|
부정 앞쪽 일치(Negative Lookahead)
/ab(?!c)/ |
(?<=)
|
뒤쪽 일치(Lookbehind)
/(?<=ab)c/ |
(?<!)
|
부정 뒤쪽 일치(Negative Lookbehind)
/(?<!ab)c/ |
// "a"는 제외하고 "b"만 +를 적용 'abababab'.match(/ab+/); // "ab" 'abbbbabbbb'.match(/ab+/); // "abbbb" // ()를 사용해 그룹화를 시키면, "ab"를 반복문자로 검색 'abababab'.match(/(ab)+/); // "abababab", "ab" 'abbbbabbbb'.match(/(ab)+/); // "ab", "ab"
정규식 캡처
패턴 그룹화]는 괄호 안에 있는 표현식을 캡처하여 사용합니다. [캡처란 간단히 매칭되는 문자열을 복사하여 변수에 저장하는 개념으로 생각하면 되는데, 다음의 예제는 ()
패턴 안에 있는 “ab”를 그룹화하여 캡처하는 것을 보여줍니다.
'abababab'.match(/(ab)+/); // "abababab", "ab"
위의 예제에서 캡처된 표현식은 당장 사용되지 않고, 그룹화된 “ab”를 패턴 +
를 사용하여 1회 이상 연속으로 반복되는 문자를 검색합니다. 이렇게 캡처 외의 표현식이 모두 작동하고 난 뒤에 캡쳐된 표현식 “ab”가 검색되는데, 순서는 다음과 같습니다.
- 그룹화된 “ab”를 패턴
+
로 1회 이상 연속으로 반복 검색 - “abababab” 반환
- 캡처된 “ab”로 검색하여 “ab”를 추가 반환
'123abc'.match(/(\d+)(\w)/); // "123a", "123", "a"
위의 정규식 예제처럼 숫자와 문자를 포함하여 검색하는 경우에는 다음과 같은 순서로 검색합니다.
- 패턴 ()안의 표현식을 순서대로 캡쳐(
\d+
,\w
) - 캡처 후 남은 표현식으로 검색
- 패턴
\d
로 숫자를 검색하되, 패턴+
로 1개 이상 연속되는 숫자를 검색(“123”) - 다음 패턴
\w
는 문자를 검색(“a” 일치) - 최종적으로 “123a”이 반환
- 첫 번째 캡처한 표현식
\d+
로 숫자를 재검색하되, 패턴+
로 1개 이상 연속되는 숫자를 검색 - “123”이 일치하여 반환
- 나머지 캡처한 표현식
\w
로 문자를 검색하여, 일치하는"a"
를 반환
캡처하지 않는 그룹화: (?:)
앞에서 살펴본 것처럼 뜻하지않은 정규식 그룹화 캡쳐로 인해 불필요한 결과값을 얻는 것이 싫다면, 괄호 안에 ?:
문자를 추가하여 캡쳐를 비활성화시킬 수 있습니다.
즉, 다음과 같이 표현식 캡처를 하지 않기 때문에 “a”와 “b”를 그룹화한 “ab”만으로 검색이 됩니다.
// 그룹화 + 캡처 "abababab".match(/(ab)+/); // "abababab", "ab" // 그룹화만 "abababab".match(/(?:ab)+/); // "abababab"