JavaScript 키워드 RegExp
🤔 왜 알아보고 싶었는가?
프론트엔드 작업을 할 때 마다 사용자의 입력을 확인하고 변경해야 할 일이 생긴다.
이럴 때 자주 사용하는 것이 정규 표현식, RegExp 이다.
당연하게 이거를 안쓰고 직접 체크할 수 있고, 변경 또한 replace 를 활용하면 된다.
하지만 이 정규표현식을 알고 사용해본 사람들이면 만드는 것이 어려울 뿐 효과는 확실하다는 것을 알 것이다.
본인도 해당 상황에 많이 사용을 했었는데 실제로 내가 원하는 정규표현식을 만들라고 하면 어려워한다.
그렇기 때문에 이번 기회에 한 번 알아보려고 한다.
🔧 정규 표현식이란?
정규 표현식의 정의는 무엇일까?
정규 표현식이란 일정한 패턴을 가진 문자열의 집합을 표현하기 위해 사용하는 형식 언어이다.
이러한 정규 표현식은 자바스크립트만 있는 것은 아니며 대다수의 프로그래밍 언어에 내장되어 있다.
그러면 이 정규표현식은 어디에 쓰일까? 바로 문자열을 대상으로 한 패턴 매칭 기능에 사용한다.
패턴 매칭 기능이란 특정 패턴과 일치하는 문자열을 검색하거나 추출 또는 치환하는 기능을 말한다.
우리가 회원가입을 할 때 주로 입력하는 것이 무엇일까?
이메일, 전화번호, 이름, 생년월일 등등 이 있을 것이다.
이것들의 구조를 생각해보면 정형화 된 친구들이 많다.
예를 들어 이메일은 [문자들]@[문자들].[문자들],
전화번호는 [숫자 2~3개] - [숫자 4개] - [숫자 4개],
생년월일은 [숫자 4개] - [숫자 1~2개] - [숫자 1~2개],
이렇게 유저들이 정확하게 입력해주면 좋겠지만 그렇지 않은 경우가 많다.
부정확하게 입력된 것을 확인하고 이를 인지시켜줘야 할 때, 우리가 생각하는 구조와 맞는지를 확인해야 한다. 이럴 때 정규 표현식을 사용할 수 있다.
const phone = '010-2222-33사4';
const regExp = /^\d{3}-\d{4}-\d{4}$/;
regExp.test(phone); // false
위 경우는 핸드폰 번호를 채크하는 정규식을 만들어서 테스트를 실행시키는 경우이다.
우리가 회원가입을 했을 때 입력한 것이 맞는지 체크해주는 것이라 보면 된다.
우리는 지금 정규 표현식이 뭔지, 왜 필요한 지를 알아보았다.
본격 적으로 어떻게 만들고 사용하는지 알아보자.
👶🏻 정규 표현식을 만들자~
정규 표현식을 만드는 방법에는 리터럴을 사용한 방법(위에서 사용), RegExp 생성자 함수를 통한 생성, 이렇게 두 가지 방법이 있다.
const regExp1 = /^\d{3}-\d{4}-\d{4}$/;
const regExp2 = new RegExp(/^\d{3}-\d{4}-\d{4}$/);
const regExp3 = new RegExp(hi, 'g');
이 두 가지 방법 중 본인이 원하는 방법을 사용해도 무방하다.
다른 점이라면 생성자 함수를 사용하는 방식에서는 플래그를 뒤로 뺄 수 있고, 입력하는 패턴의 앞 뒤의 / 를 생략할 수 있다.
본인이 생각하기에는 리터럴 방식이 더 간단해보여서 해당 방식을 기준으로 글을 이어갈 생각이다.
그러면 내부에 들어가는 것은 무엇일까?
정규식은 크게 패턴과 플래그로 구성된다.
/ 의 경우는 시작기호, 종료기호를 나타내며, 내부에 들어가있는 것이 패턴, 패턴 뒤에 붙는 것이 플래그이다.
const regExp = /pattern/gi; // 시작기호(/), 패턴, 종료기호(/), 플래그 순이다.
우리는 지금 어떻게 만드는지 구조에 대해서 배웠다.
그러면 차후 알아볼 것은 아래와 같을 것이다.
- 정규 표현식으로 쓸 수 있는 메서드는?
- 정규 표현식의 플래그는 무엇이 있을까?
- 정규 표현식의 패턴은 어떻게 만들까?
하나씩 살펴보도록 하자
🔧 정규 표현식으로 쓸 수 있는 메서드는?
주로 우리는 정규 표현식을 특정 문자 구조가 맞는지를 검사하는데 사용한다.
그렇다면 그런 기능을 제공하는 메서드가 있을 것이다.
크게 exec, test, match 등을 사용할 수 있다.
하나씩 살펴보자.
exec
exec 는 인수로 전달받은 문자열에 대해 정규 표현식의 패턴을 검색하여 매칭 결과를 배열로 반환한다. 이 때 매칭 결과가 없는 경우 null 을 반환한다.
const target = 'Is this all is?';
const regExp = /is/;
regExp.exec(target);
// ["is", index: 5, input: "Is this all is?", groups: undefined]
이 때 주의해야 할 것은 문자열 내의 모든 패턴을 검색하는 g 플래그를 설정을 해도 첫 번째 매칭 결과만 반환한다는 점을 주의해야 한다.
test
test 는 인수로 전달받은 문자열에 대해 정규 표현식의 패턴을 검색하여 매칭 결과를 불리언 값으로 반환한다.
const target = 'Is this all is?';
const regExp = /is/;
regExp.test(target); // true
match
match 는 위 두 메서드와는 다르게 String 의 프로토타입 객체에 있는 메서드이다.
위 두 개는 RegExp 의 프로토타입 객체에 있는 메서드이다.
match 는 대상 문자열과 인수로 전달받은 정규 표현식과의 매칭 결과를 배열로 반환한다.
const target = 'Is this all is?';
const regExp1 = /is/;
const regExp2 = /is/g;
target.match(regExp1); // ["is", index: 5, input: "Is this all is?", groups: undefined]
target.match(regExp2); // ["is", "is"]
exec 와 유사해보이나 다른 점이 있다면 모든 패턴을 검색하는 g 플래그를 설정하면 모든 매칭 결과를 배열로 반환한다는 차이가 있다.
⛳️ 정규 표현식의 플래그는 무엇이 있을까?
플래그는 정규 표현식의 검색 방식을 설정하기 위해서 사용한다.
총 6개의 플래그가 있는데 이 중에서 자주 사용할 3개를 살펴보도록 하자.
그 전에 플래그 설명을 조금 이어가자면
플래그는 옵션이다. 따라서 옵션을 아에 선택하지 않아도 무방한데 이럴 경우 디폴트는 대소문자를 구별하고 패턴 매칭이 여러번 일어나도 맨 처음의 값만 찾고 종료된다.
또한 플래그는 여러개를 사용해도 좋은데 이는 예제코드에서 보여주도록 하겠다.
- i
- ignore case 라는 의미를 담고 있다.
- 대소문자를 구별하지 않고 패턴을 검색하는 경우 사용한다.
- g
- global 이라는 의미를 담고 있다.
- 대상 문자열 내에서 패턴과 일치하는 모든 문자열을 전역 검색한다.
- m
- multi line 이라는 의미를 담고 있다.
- 문자열의 행이 바뀌더라도 패턴 검색을 계속한다.
const target = 'Is this all is?';
target.match(/is/);
// ["is", index: 5, input: "Is this all is?", groups: undefined]
target.match(/is/i);
// ["Is", index: 0, input: "Is this all is?", groups: undefined]
target.match(/is/g);
// ["is", "is"]
target.match(/is/gi);
// ["Is", "is", "is"]
👨🏻🔧 정규 표현식의 패턴은 어떻게 만들까?
정규 표현식에서 패턴은 문자열의 일정한 규칙을 표현하기 위해 사용한다.
이는 우리가 앞에서 살펴본 예제 코드에서도 확인할 수 있다.
해당 방식처럼 궁금한 문자열을 넣을 수도 있지만 특별한 의미를 가지는 메타문자를 활용해서 처리를 할 수 있다.
이러한 경우에 집중해서 한번 살펴보려한다.
임의의 문자열을 검색
아무런 문자가 와도 상관 없어요~ 를 표현하기 위해서 우리는 . 을 사용할 수 있다.
알파벳, 숫자, 특수문자, 빈칸 등등이 다 매칭이 된다.
아래 예제코드를 보면 이해할 수 있다.
const target = 'Is this all there is?';
const regExp = /.../g;
target.match(regExp);
// ["Is ", "thi", "s a", "ll ", "the", "re ", "is?"]
반복 검색
우리는 특정 문자가 반복되는 것을 찾고 싶을 수 있다.
또한 그 문자가 몇 번까지 반복되는 지 모를 때도 있다.
이럴 때 , +, ? 를 사용할 수 있다.
{m, n} 을 통해서 우리는 앞선 패턴을 최소 m번, 최대 n번 반복되는 문자열을 찾아낼 수 있다. 예제를 살펴보면서 아 이렇게 쓸 수 있구나 확인해보길 바란다.
+ 는 앞선 패턴이 최소 한번 이상 반복되는 문자열을 의미한다.
즉 {1,} 과 같다. 이 또한 예제를 통해 빠르게 이해할 수 있다.
? 의 경우에는 앞선 패턴이 최대 한 번이상 반복되는 문자열을 의미한다.
{0,1} 이라고 생각하면 쉽다. 있어도 되고 없어도 되는 문자를 처리할 때 사용하면 된다.
const target1 = 'A AA B BB Aa Bb AAA';
// 시작 n, 끝 m 값을 모두 넣어준 경우
const regExp1 = /A{1,2}/g;
// 끝 값을 안넣어준 경우 -> 이 경우는 {n,n} 으로 동작해 정확하게 n 번 반복만 찾는다.
const regExp2 = /A{2}/g;
// 끝 값을 공란으로 비운 경우 -> 이 경우는 n 번 이상 반복되는 문자열을 찾는다.
const regExp3 = /A{2,}/g;
// + 의 경우 -> {1,} 이라 생각하면 된다.
const regExp4 = /A+/g;
// ? 의 경우 -> {0,1} 이라 생각하면 된다.
const target2 = 'color colour';
const regExp5 = /colou?r/g;
target1.match(regExp1); // ["A", "AA", "A", "AA", "A"]
target1.match(regExp2); // ["AA", "AA"]
target1.match(regExp3); // ["AA", "AAA"]
target1.match(regExp4); // ["A", "AA", "A", "AAA"]
target2.match(regExp5); // ["color", "colour"]
또는(OR) 검색
이놈 또는 저놈만 있으면 된다! 를 표현하기 위해서 우리는 | 기호를 사용한다.
논리 연산에 사용하던 그 기호 맞다. 그렇기에 예제를 보면서 한번 이해해보자.
const target = 'A AA B BB Aa Bb AAA';
const regExp = /A|B/g;
target.match(regExp); // ["A", "A", "A", "B", "B", "B", "A", "B"]
하지만 생각을 해보면 이거는 너무 귀찮은 경우도 있을 것이다.
왜냐하면 우리는 알파벳으로만 몇 자 이상 같은 경우를 사용할 때도 있을 것이다.
이럴 때는 모든 알파벳을 | 로 처리해야 할까?
이런 경우를 위해서 [] 라는 좋은 도구가 있다.
[] 안에 or 처리할 문자들을 넣어두면 된다.
또한 더 좋은 처리가 가능한데 예를 들어서 알파벳, 숫자 같은 경우는 [A-Z], [a-z], [0-9] 라는 방식으로 처리가 가능하다. 이는 예제를 통해서 더 알아보자.
const target1 = 'A AA B BB Aa Bb AAA';
// 대문자만 이어진 경우
const regExp1 = /[A-Z]+/g;
// 대소문자 구분없이 이어진 경우
const regExp2 = /[A-Za-z]+/g;
target1.match(regExp1); // ["A", "AA", "B", "BB", "A", "B", "AAA"]
target1.match(regExp2); // ["A", "AA", "B", "BB", "Aa", "Bb", "AAA"]
const target2 = '12,345';
// 숫자로만 이어진 경우
const regExp3 = /[0-9]+/g;
// 숫자와 쉼표로 이어진 경우
const regExp4 = /[0-9,]+/g;
target2.match(regExp3); // ["12", "345"]
target2.match(regExp4); // ["12,345"]
위 에제 코드를 더 간단하게 하기 위해 제공되는 것들도 있다. 이는 다음과 같다.
- \d: 숫자를 의미한다. [0-9] 와 같다고 보면 좋다.
- \w: 알파벳, 숫자, 언더스코어를 의미한다. [A-Za-z0-9_] 와 같다고 보면 좋다.
- \W: \w 를 제외한 나머지를 의미한다.
- \s: 여러가지 공백 문자를 의미한다. [\t\r\n\v\f] 와 같은 의미이다.
NOT 검색
앞서 알아본 [] 안에 ^ 기호를 사용하면 not 의 의미를 가진다.
예를 들어서 [^0-9] 라고 우리가 패턴을 만든다면 이는 숫자를 아에 제외한다는 뜻이다.
const target = 'AA BB 12 Aa Bb';
const regExp = /[^0-9]+/g;
target.match(regExp); // ["AA BB ", " Aa Bb"]
시작 위치로 검색, 마지막 위치로 검색
[] 밖에서 ^ 를 사용하면 문자열의 시작을 의미하고,
$ 표시는 문자열의 마지막을 의미한다.
한마디로 접두사, 접미사 관련 처리를 할 수 있다는 것이다.
const target = 'https://test.com';
const regExp1 = /^https/;
const regExp2 = /com$/;
regExp1.test(target); // true
regExp2.test(target); // true
😃 마무리 소감
나름은 자주 사용하던 정규 표현식인데 매번 검색하면서 오.. 이거.. 하면서 사용을 했었는데 이제는 조금이나마 이해를 한 것 같다.
물론 이를 익숙하게 사용하고 하려먼 자주 사용해보고 고민해보는 시간이 필요할 것이라고 보지만 문법이나 사용방식을 익혔다는 점에서 만족스러운 학습 정리였다.
또 사용하면서 꿀팁이라던지 자주 사용하는 친구들이 있다면 소개를 해보도록 할 예정이다.
일단은 막 사용해보도록 해보자! 아자자!!!