
코드를 짜다보면 전화번호, 이메일 등의 체크 형식에서 정규표현식을 종종 사용하는 경우가 있는 데, 한눈에 봤을 때 코드를 이해하기 어려운 경우가 종종있었다. 어떤 방식으로 정규표현식을 작성하는지 알아보기 위해 공부해보았다.
정규 표현식(regular expression)은 문자 검색과 교체에 사용되는 패턴이다. 자바스크립트에서는 RegExp 객체와 문자열 메서드를 조합하여 정규표현식을 사용할 수 있다.
정규 표현식은 패턴과 선택적으로 사용할 수 있는 플래그로 구성된다.
정규식 객체를 만들 때는 두 가지 문법이 사용된다.
regexp = new RegExp("pattern", "flags");
/를 사용한다.regexp = /pattern/; // 플래그가 없음
regexp = /pattern/gim; // 플래그 g, m, i 가 있음
/는 자바스크립트에 정규 표현식을 생성하고 있다는 것을 알린다. 문자열에 따옴표를 쓰는 것과 동일한 역할
짧은 문법이든 긴 문법이든 상관없이 regexp는 내장 클래스 RegExp의 인스턴스가 된다.
단, 두 문법의 차이점은 /.../를 사용하면 문자열 템플릿 리터럴에서 ${...}를 사용했던 것처럼 중간에 표현식을 넣을 수 없다. 슬래시를 사용한 방법은 완전히 정적이기 때문이다.
짧은 문법을 사용할 때는 코드를 작성하는 시점에 패턴을 알고 있을 때 사용한다. 반면 긴 문법은 상황에 따라 동적으로 생성된 문자열을 가지고 정규 표현식을 만들어야 할 때 주로 사용한다.
let tag = prompt("어떤 태그를 찾고 싶은가요?", "h2");
let regexp = new RegExp(`<${tag}>`); // 프롬프트에서 'h2'라고 대답한 경우, /<h2>/와 동일한 역할을 한다.
pattern:i : i플래그가 붙으면 대소문자 구분없이 검색한다. Ignore casepattern:g : g플래그가 붙으면 패턴과 일치하는 모든 것들을 찾는다. g가 없으면 패턴과 일치하는 첫 번째 결과만 반환된다. Globalpattern:m : 다중 행 모드(multiline mode)를 활성화한다.(여러행 검색)pattern:s : pattern:.이 개행문자 \n도 포함하도록 dotail 모드를 활성화한다.pattern:u : 유니코드 전체를 지원한다. 이 플래그를 사용하면 서로게이트 쌍을 올바르게 처리할 수 있다.pattern:y : 문자 내 특정 위치에서 검색을 진행하는 sticky 모드를 활성화 시킨다.str.match(regexp)에는 3가지 모드가 있다.pattern:g가 붙으면 패턴과 일치하는 모든 것을 담은 배열을 반환let str = 'We will, we will rock you';
alert(str.match(/we/gi)); // We, we
/**
* g : 패턴과 일치하는 모든것
* i : 대소문자 구분 없음
* /
pattern:g가 붙지 않은 경우에는 패턴에 맞는 첫 번째 부분 문자열만 담은 배열을 반환. 해당 문자열은 배열 인덱스 0에 저장되는데, 문자열의 프로퍼티에는 상세한 추가 정보가 저장된다.let str = "We will, we will rock you";
let result = str.match(/we/i);
alert(result[0]); // We
alert(result.length); // 1
alert(result.index); // 0 (부분 문자열의 위치)
alert(result.input); // We will, we will rock you (원본문자열 )
pattern:g의 유무와 상관없이 패턴과 일치하는 부분 문자열을 찾지 못한 경우에는 null이 반환된다.let matches = "JavaScript".match(/HTML/); // matches에는 null이 저장
if (!matches.length) {
// TypeError
//code
}
str.match 호출 결과가 항상 배열이 되게 하려면 아래와 같이 사용한다.let matches = "JavaScript".match(/HTML/) || [];
if (!matches.legnth) {
alert("정규 표현식과 일치하는 부분 문자열이 없다.");
}
str.replace(regexp, replacement)를 사용하면 regexp에 일치하는 부분 문자열을 replacement로 교체할 수 있다.console.log("We will, we will".replace(/we/i, "I")); // I will, we will
replacement는 문자열인데, 문자열 안에 아래 특수문자를 넣으면 독특한 방식으로 문자열을 교체할 수 있다.
$& : 패턴과 일치하는 부분 문자열
$` : 문자열 일부를 일치 전에 삽입
$' : 문자열 일부를 일치 후에 삽입
$n : n이 1~2자리 숫자일 경우, n번째 괄호 내용을 삽입
$$ : $문자를 삽입
let str = "I love JavaScript";
let regexp = /LOVE/i;
alert(regexp.test(str)); // true
문자 클래스는 특정 집합에 포함된 모든 기호에 일치하는 특별한 표현이다.
문자 클래스에는 다음과 같은 클래스가 있다.
pattern:\d : 숫자
pattern:\D : 숫자가 아닌 문자
pattern:\s : 스페이스, 탭, 줄 바꿈 문자
pattern:\S : 스페이스, 탭, 줄바꿈문자를 제외한 모든 문자
pattern:\w : 라틴문자, 숫자, 밑줄_
pattern:\W : 라틴문자, 숫자, 밑줄을 제외한 모든 문자
pattern:. : 정규표현식 's'플래그가 있으면 모든 문자, 없으면 줄바꿈을 제외한 모든 문자
let str = "+7(903)-123-45-67";
let regexp = /\d/;
alert(str.match(regexp)); // 7 , 가장 먼저 만난 숫자가 7
let regexp2 = /\d/g;
console.log(str.match(regexp2)); //['7', '9', '0', '3', '1', '2', '3', '4', '5', '6', '7']
console.log(str.match(regexp).join("")); // 79035419441
let str = "Is there CSS4?";
let regexp = /CSS\d/;
console.log(str.match(regexp)); // CSS4
console.log("I love HTML5".match(/\s\w\w\w\w\d/)); // 'HTML5'
let str = "+7(903)-123-45-67";
alert(str.replace(/\D/g, "")); // 숫자가 아닌 문자를 찾아 문자열에서 없애버리는 것
pattern : .은 줄 바꿈 문자를 제외한 모든 문자와 일치하는 특별한 문자 클래스이다.alert("Z".match(/./)); // Z
let regexp = /CS.4/;
alert("CSS4".match(regexp)); // CSS4
alert("CS 4".match(regexp)); // CS 4 (공백도 문자이기때문에 출력된다)
alert("CS4".match(/CS.4/)); // null, 점과 일치하는 문자가 없기 때문에
\n과 일치하지 않음pattern:s를 사용하면 점은 모든 문자와 일치alert("A\nB".match(/A.B/)); // null
alert("A\nB".match(/A.B/s)); // A\nB
pattern:u플래그로 정규 표현식에서 유니코드 기능을 활성화할 수 있다.
\p{...}를 이용하여 유니코드 프로퍼티를 검색에 사용할 수 있다.유니코드 프로퍼티를 사용하면 특정 단어의 단어, 따옴표나 통화 단위같은 특수 문자 등을 모두 검색할 수 있다.
자바스크립트는 문자열에 유니코드 인코딩을 사용한다.
문자는 하나인데 길이가 2가 나오는 경우
length는 4바이트 문자를 2바이트 문자 2개로 취급. 4바이트를 하나로 묶어서 취급해야 하므로 올바르지 않은 결과이다. (서로게이트 쌍)
alert("😄".length); // 2
alert("𝒳".length); // 2
기본적으로는 정규표현식도 4바이트의 긴 문자를 2바이트 문자 2개로 취급한다. 문자열의 경우처럼 이런 방식은 잘못된 결과로 이어질 수 있다.
문자열과 다르게 정규표현식에는 이런 문제를 해결할 수 있는 pattern:u플래그가 있다. 이를 사용하면 유니코드 프로퍼티를 사용한 검색이 가능해진다.
pattern:\p{...}를 사용하면 프로퍼티를 통해 문자를 찾을 수 있다. 이를 사용하기 위해서는 정규 표현식에 pattern:u플래그가 반드시 있어야 한다.
let str = "A ბ ㄱ";
alert(str.match(/\p{L}/gu)); // A,ბ,ㄱ
alert(str.match(/\p{L}/g)); // null ('u' 플래그가 없어서 일치 결과 없음)
다음은 주요 문자 범주와 각각의 하위 범주 목록
문자(Letter) L
LlLmLtLuLo숫자(Number) N
NdNlNo문장 부호(Punctuation) P
PcPdPiPfPsPePo표시(Mark) M(강세 등)
McMeMn기호(Symbol) S
ScSkSmSo구분 기호(Separator) Z
ZlZpZs기타(other) C
CcCfCnCoCs소문자를 찾을 때 pattern:\p{Ll}, 문장부호를 찾을 때pattern:\p{P}등으로 검색할 수 있다.
참고할 수 있는 문서
pattern:^와 달러기호 pattern:$는 정규식에서 앵커라는 뜻을 지닌다.// ^Mary ==> 문자열이 Mary로 시작하는지 검사
// snow$ ==> 문자열이 snow로 끝나는지 검사
let str = "Mary and a little lamb";
alert(/snow$/.test(str)); // true
pattern:^...$는 문자열이 패턴과 완전히 일치하는지 확인할 때 자주 사용된다. 사용자 입력 내용이 올바른 형식으로 되어있는지 확인할 때가 대표적인 예let goodInput = "12:34";
let badInput = "12:345";
let regexp = /^\d\d:\d\d$/;
alert(regexp.test(goodInput)); // true
alert(regexp.test(badInput)); // false
pattern:m플래그를 사용하면 여러 행 모드(multiline mode)를 활성화할 수 있음pattern:^, pattern:$의 작동방식에만 영향을 준다.let str = `1st place: Winnie
2nd place: Piglet
3rd place: Eeyore`;
alert(str.match(/^\d/gm)); // 1, 2, 3
alert(str.match(/^\d/g)); // 1 , m플래그가 없으면 맨 앞 숫자만 검색된다.
let str = `Winnie: 1
Piglet: 2
Eeyore: 3`;
alert(str.match(/\d$/gm)); // 1,2,3
pattern:^, pattern:$뿐만아니라 \n도 사용할 수 있다.let str = `Winnie: 1
Piglet: 2
Eeyore: 3`;
alert(str.match(/\d\n/gm)); // 1,2
/*
3뒤에는 줄바뀜문자가 없어서 미출력됨.
*/
exec
test
match
search
replace
split
a|b식으로 사용/[abc]/ : a or b or c 를 포함하는[다-바] : 다 or 라 or 마 or 바[^lgen] 'l' 'g' 'E' 'n' 4개 문자를 제외/^www//com$/어떠한 패턴이 얼만큼 등장하는지
* : 0개 이상 나타나는 문자
a*b : a가 앞에 있을 수도 있고, 여러개 있을 수도 있고 b도 뒤에 있을 수도 있고, 여러 개 있을 수도 있음. 'aab','ab' 모두 가능하다+ : 1개 이상 나타나는 문자
a+b : a가 한개이상, b도 한개 이상 있어야한다. 'ab', 'aabb', 'abb' ..? : 없거나 1개인 경우
a?b : a가 없거나 1개, b가 없거나 1개. 'b', 'ab'..{m,n} : m회 이상 n회 이하 나타나는 문자
[els]{1,3} : e or l or s 가 1개 이상 3개 이하