프로그래머스 코테를 풀면 어김 없이 정규표현식을 활용한 쿨한 풀이를 마주한다. 아직 다른 메서드들도 자유자재로 쓰는 편은 못되어 정규표현식은 조금 뒤로 미뤄두었는데, 점점 마주하게 되는 빈도가 늘어나면서 정리를 한 번 다시 해야겠단 생각이 들었다. 잘 습득해서 쿨해지자.
정규표현식
정규표현식, 또는 정규식은 문자열에서 특정 문자 조합을 찾기 위한 패턴이다. Javascript 에서는 정규표현식도 객체로서, RegExp의 exec()와 test() 메서드를 사용할 수 있다. String의 match(), matchAll(), replace(), replaceAll(), search(), split() 메서드와도 함께 사용할 수 있다.
정규표현식 만들기
정규표현식은 두 가지 방법으로 만들 수 있다.
- 정규표현식 리터럴. 슬래시로 패턴을 감싸서 작성한다.
정규표현식 리터럴은 패턴과 플래그로 구성된다.
const re = /ab+c/
- RegExp 객체의 생성자 호출.
생성자 함수를 사용하면 정규표현식이 런타임에 컴파일된다. 바뀔 수 있는 패턴이나, 사용자 입력 등 외부 출처에서 가져오는 패턴의 경우 이렇게 사용하면 된다.
const re = new RegExp('ab+c')
RegExp 메서드
RegExp.prototype.exec 메서드
exec 메서드는 인수로 전달 받은 문자열에 대해 정규표현식의 패턴을 검색하여 매칭 결과를 배열로 반환한다. 매칭 결과가 없는 경우 null을 반환한다.
const target = 'Is this all there is?';
const regExp = /is/;
regExp.exec(target);
// -> ["is", index: 5, input: "Is this all there is?", groups: undefined]
exec 메서드는 문자열 내의 모든 패턴을 검색하는 g 플래그를 지정해도 첫 번째 매칭 결과만 반환하므로 주의해야한다.
RegExp.prototype.test 메서드
test 메서드는 인수로 전달 받은 문자열에 대해 정규표현식의 패턴을 검색하여 매칭 결과를 불리언 값으로 반환한다.
const target = 'Is this all there is?';
const regExp = /is/;
regExp.test(target); // -> true
String.prototype.match 메서드
String 표준 빌트인 객체가 제공하는 match 메서드는 대상 문자열과 인수로 전달 받은 정규표현식과의 매칭 결과를 배열로 반환한다.
const target = 'Is this all there is?';
const regExp = /is/;
target.match(regExp);
// -> ["is", index: 5, input: "Is this all there is?", groups: undefined]
exec 메서드는 문자열 내의 모든 패턴을 검색하는 g 플래그를 지정해도 첫 번째 매칭 결과만 반환한다. 하지만 String.prototype.match 메서드는 g 플래그가 지정되면 모든 매칭 결과를 배열로 반환한다.
const target = 'Is this all there is?';
const regExp = /is/g;
target.match(regExp);
// -> ["is", "is"]
자주 쓰이는 주요 메서드 한 눈에 정리
메서드 | 의미 |
("문자열").match(/정규표현식/플래그) | "문자열"에서 "정규표현식"에 매칭되는 항목들을 배열로 반환 |
("문자열").replace(/정규표현식/, "대체문자열") | "정규표현식"에 매칭되는 항목을 "대체문자열"로 변환 |
("문자열").split(정규표현식) | "문자열"을 "정규표현식"에 매칭되는 항목으로 쪼개어 배열로 반환 |
(정규표현식).test("문자열") | "문자열"이 "정규표현식"과 매칭되면 true, 아니면 false 반환 |
(정규표현식).exec("문자열") | match 메서드와 유사(단, 무조건 첫 번째 매칭 결과만 반환) |
플래그
패턴과 함께 정규표현식을 구성하는 플래그는 정규표현식의 검색 방식을 설정하기 위해 사용한다. 주로 g, i, m 플래그 위주로 사용된다.
플래그 | 설명 | 대응하는 속성 |
d | 부분 문자열 일치에 대해 인덱스 생성 | RegExp.prototype.hasIndices |
g | 전역 탐색 | RegExp.prototype.global |
i | 대소문자를 구분하지 않음 | RegExp.prototype.ignoreCase |
m | 여러 줄에 걸쳐 탐색 | RegExp.prototype.multiline |
s | 개행 문자가 . 과 일치함 | RegExp.prototype.dotAll |
u | "unicode", 패턴을 유니코드 코드 포인트의 시퀀스로 간주함 | RegExp.prototype.unicode |
y | "접착"탐색, 대상 문자열의 현재 위치에서 탐색을 시작함. | RegExp.prototype.sticky |
플래그는 옵션이므로 선택적으로 사용할 수 있으며, 순서와 상관없이 하나 이상의 플래그를 동시에 설정할 수도 있다. 어떠한 플래그를 사용하지 않은 경우 대소문자를 구별해서 패턴을 검색한다. 그리고 문자열에 패턴 검색 매칭 대상이 1개 이상 존재해도 첫 번째 매칭한 대상만 검색하고 종료한다.
const target = 'Is this all there is?';
//target 문자열에서 is 문자열을 대소문자 구별하여 한 번만 검색한다.
target.match(/is/);
// -> ["is", index: 5, input: "Is this all there is?", groups: undefined]
//target 문자열에서 is 문자열을 대소문자 구별하지 않고 한 번만 검색한다.
target.match(/is/i);
// -> ["Is", index: 0, input: "Is this all there is?", groups: undefined]
//target 문자열에서 is 문자열을 대소문자 구별하여 전역 검색한다.
target.match(/is/g);
// -> ["is", "is"]
//target 문자열에서 is 문자열을 대소문자 구별하지 않고 전역 검색한다.
target.match(/is/ig);
// -> ["Is", "is", "is"]
정규표현식 패턴 작성하기
정규표현식 패턴은 /abc/ 처럼 단순한 문자로 구성하거나, /ab+c/ 와 /Chapter (\d+)\.\d*/ 처럼 단순한 문자와 특수 문자의 조합으로 구성할 수도 있다. 특히 (\d+)에 나타난 괄호는 정규표현식에서 기억 장치처럼 쓰여서 괄호의 안쪽 패턴과 일치한 부분을 나중에 사용할 수 있도록 기억한다.
단순 패턴 사용하기
단순 패턴은 문자열을 있는 그대로 탐색할 때 사용한다. 예를 들어, /abc/ 패턴은 문자열에서 정확한 순서로 "abc"라는 문자의 조합이 나타나는 부분과 일치한다. 그러므로 이 패턴은 "Hi, do you know your abc's?" 와 "The latest airplane designs evolved from slabcraft." 두 문자열에서 일치에 성공하고, 일치하는 부분은 "abc"일 것이다. 반면 "Grab crab"에서는 일치하지 않는데 이 문자열은 부분 문자열로 "ab c"를 포함하지만, 정확하게 "abc"가 아니기 때문이다.
특수 문자 사용하기
하나 이상의 "b"를 찾는다거나 공백 문자를 찾는 등 직접적인 일치 이상의 탐색이 필요할 땐 특수 문자를 사용한다. 예컨대 하나의 "a" 이후에 0개 이상의 "b", 그 뒤의 "c"와 일치해야 하면 /ab*c/ 패턴을 사용할 수 있다. "b" 뒤의 *는 "이전 항목의 0번 이상 반복"을 의미한다. 이 패턴을 문자열 "cbbabbbbcdebc"에 대해 사용하면 일치하는 부분 문자열은 "abbbc"일 것이다.
정규표현식 매칭 패턴
아래 매칭 패턴을 사용하면, 훨씬 쉽게 문자/숫자/기호를 표현할 수 있다.
패턴 | 의미 |
a-z A-Z |
영어 알파벳(-으로 범위 지정) |
ㄱ-ㅎ 가-힣 |
한글 문자(-으로 범위 지정) |
0-9 | 숫자(-으로 범위 지정) |
. | 모든 문자열(숫자, 한글, 영어, 특수기호, 공백 모두! 단, 줄바꿈 X) |
\d | 숫자 |
\D | 숫자가 아닌 것 |
\w | 영어 알파벳, 숫자, 언더스코어(_) |
\W | \w가 아닌 것 |
\s | space 공백 |
\S | space 공백이 아닌 것 |
\특수기호 | 특수기호 |
정규표현식 검색 패턴
아래 패턴들을 이용하면 AND, OR, StartWIth, EndWith 등의 다양한 조합을 만들 수 있다.
기호 | 의미 |
? | 최대 한 번 (없음 || 한 개) |
* | 없거나 있거나 (없음 || 있음) : 여러개 포함 |
+ | 최소 한 개 (한 개 || 여러개) |
{n} | n개 |
{Min,} | 최소 Min 개 이상 |
{Min,Max} | 최소 Min 개 이상, 최대 Max개 이하 |
활용 샘플 코드
웹사이트 주소 정규표현식
http:// 나 https:// 로 시작하고, 알파벳, 언더스코어(_), 하이픈(-), 닷(.)으로 이루어져 있다.
const text = '대나무 빨대 구입 문의 : http://dogumaster.com http://google.com 010-1111-2222 02-333-7777 curryyou@aaa.com';
text.match(/https?:\/\/[\w\-\.]+/g);
//["http://dogumaster.com", "http://google.com"]
여기서 사용된 정규표현식을 해석해보면,
/https?:\/\/[\w\-\.]+/g
1) http 로 시작하고,
2) s? 다음에 s는 없거나 있고,
3) : 다음에 : 가 오고,
4) \/\/ 다음에 특수기호 // 가 오고,
5) [\w\-\.]+ \w(영문자, 언더스코어), 하이픈, 닷으로 이루어진 문자열이 한 개 이상(+) 있다.
6) g 매칭되는 것을 모두 다 찾는다.
전화번호 정규표현식
유선번호라면 02-111-2222 형식이고, 핸드폰 번호라면 010-1111-2222 형식이다. 숫자의 갯수가 다르다.
const text = '대나무 빨대 구입 문의 : http://dogumaster.com http://google.com 010-1111-2222 02-333-7777 curryyou@aaa.com';
text.match(/\d{2,3}-\d{3,4}-\d{4}/g);
// ['010-1111-2222', '02-333-7777']
/\d{2,3}-\d{3,4}-\d{4}/g
1) \d{2,3}. 숫자 2~3개로 시작하고,
2) - 다음에 하이픈이 오고,
3) \d{3,4} 다음에 숫자 3~4개가 오고,
4) - 다음에 하이픈이 오고,
5) \d{4} 다음에 숫자 4개가 온다.
6) g 매칭되는 것을 모두 다 찾는다.
이메일주소 정규표현식
xxx@xxxx.com 등의 형식
const text = '대나무 빨대 구입 문의 : http://dogumaster.com http://google.com 010-1111-2222 02-333-7777 curryyou@aaa.com';
text.match(/[\w\-\.]+\@[\w\-\.]+/g); //['curryyou@aaa.com']
특수기호 정규표현식
모든 특수기호 나열
const regex = /\[\]\{\}\/\(\)\.\?\<\>!@#$%^&*/g
문자와 숫자가 아닌 것을 매칭([^문자] 패턴으로 Not 기능 적용)
const regex = /[^a-zA-Z0-9가-힣ㄱ-ㅎ]/g
'JavaScript' 카테고리의 다른 글
[JavaScript] == 와 === 의 차이 (0) | 2023.09.19 |
---|---|
DFS(Depth-First Search) : 재귀함수와 스택 프레임 (0) | 2023.08.05 |
[JavaScript] 최대공약수(GCD) & 최소공배수(LCM) 구하기 (0) | 2023.07.11 |
[JavaScript] 배열 splice 메서드 (0) | 2023.07.09 |
[JavaScript] Set (0) | 2023.07.06 |