회원가입 API를 만들던 중 아이디 부분을 검사하려고 한다.
정말 생각나는대로 만들어보자면 아래와 같은 함수를 이용할 수 있을 것이다.
const idSearch = function (email) {
// '@'의 인덱스 찾기
const lastIndex = email.indexOf('@');
// 첫 번째 문자부터 '@' 전까지 추출
return email.slice(0, lastIndex);
}
이메일은 '@'이라는 특수 문자가 중간에 있는 문법이라서 비교적 찾는게 간단하다. 그런데 만약 닉네임에 대한 특수문자 검사라던지, 영어 대/소문자 구분을 하려면 일일이 다 비교해야 할까?
만약에 그렇게 한다면 해당 함수를 만드는 데만 한나절을 넘게 걸릴 것이다.
하지만! 프로그래머라면 만사 모든게 귀찮다고 여기고 효율적으로 일을 해야하는 법. 이미 이런 방법을 대비해 문자열을 추출하거나 색인할 수 있는 방법이 있는데, 바로 정규 표현식(Regular Expression)이다!
영어로 짧게 줄여서 regex 혹은 regexp라고 부르는 정규 표현식[1]은 문자열에서 특정한 문자를 찾아내는 도구이자 일종의 언어다.
왜 일종의 언어라고 하냐면, 일부 라이브러리처럼 누군가 편하게 작업하기 위해 만들어놓은 모듈이 아니라 특수한 문법을 가진 형식이기 때문이다.
한국어로는 정규식이라고 짧게 줄여 말하기도 하며, 정규가 붙었다고 해서 해당 표현식이 문법에 맞는 것 혹은 인정된 것이 아니다. 🙅🏻
정규 표현식에 대한 구체적인 문법과 내용은 상당히 많기 때문에 이번에는 자바스크립트에서 사용하는 방법만 소개한다.
정규 표현식은 크게 두 가지 단계로 이루어진다. 하나는 컴파일(Compile) 단계와 실행(Excution) 단계 이다.
컴파일 단계는 패턴을 만드는 과정이다. 자바스크립트에서 정규 표현식을 만드는 방법은 두 가지가 있는데 하나는 리터럴 방식과 생성자를 이용하는 방식이다.
리터럴 방식은 스크립트를 불러올 때 컴파일된다. 정규 표현식이 변하지 않는 상수라면 리터럴 방식을 사용하는 것이 좋다.
반면에 생성자 함수는 런타임 시 컴파일 된다. 사용자 입력에 따라 동적으로 패턴이 변하는 경우 생성자 함수를 사용하는 것이 좋다.
// 정규 표현식 리터럴
const pattern1 = /a/;
// 정규 표현식 생성자
const pattern2 = new RegExp('a');
자바스크립트 정규 표현식에서 많이 쓰이는 메소드는 exec() 과 test() 가 있다.
exec() 함수는 문자열에서 일치하는 부분이 있으면 일치 정보를 나타내는 배열을 반환하고, 일치하는 부분이 없으면 null을 반환한다.
test() 함수는 문자열에서 일치하는 부분이 있으면 ture를, 없으면 false를 반환한다.
// 'a'라는 문자가 있는지 확인하는 정규 표현식
const pattern = /ii/;
// exec() 함수 예시
console.log(pattern.exec('Hawaii')); // ["a"] 출력, 두 개의 'a'가 출력되는게 아님
// test() 함수 예시
console.log(pattern.test('hello')); // false 출력
정규 표현식에는 옵션들이 여러개 있다.
i라는 옵션을 사용하면 영어의 대소문자를 구분하지 않는다.
const pattern1 = /a/;
console.log(pattern1.exec('ABCDE')); // null 출력
const pattern2 = /a/i;
console.log(pattern2.exec('ABCDE')); // ['A'] 출력
g라는 옵션을 사용하면 검색된 모든 결과를 반환한다.
const pattern1 = /a/;
console.log('abcdea'.match(pattern1)); // ['a'] 출력
const pattern2 = /a/g;
console.log('abcdea'.match(pattern2)); // ['a', 'a'] 출력
괄호를 사용하면 하나의 변수로 사용하거나 그룹화를 하여 여러 개의 문자 범위를 설정할 수 있다.
// 'abc'라는 문자열을 검색
const pattern1 = /[abc]/;
// 0 ~ 5 까지의 숫자를 검색
const pattern2 = /[0-5]/;
특수 문자를 있는 그대로 탐색하려는 경우, 특수 문자 앞에 역슬래시()를 배치해서 이스케이프 해야 한다.
이스케이프 한다는 것은 특수 문자를 문법의 형식으로 받아들이지 않고 문자 그대로 읽는다는 의미다.
// '*'를 이스케이핑 할 경우
const pattern = /a+\*b/;
[^] : 해당 문자를 제외한 나머지
^ : 문자열이나 행의 처음
$ : 문자열이나 행의 끝
\n : 일치하는 n번째 패턴
* : 0회 이상
정규 표현식에 대한 내용은 추후 별도로 포스팅해서 다룰 예정이다.