-
[JavaScript] 정규 표현식(Regular Expression) 정리Front-End/JavaScript 2022. 9. 21. 06:16
🍀 목차
글의 목적
정규 표현식이 뭘까?
in JavaScript
응용 모음
시간 복잡도
학습에 도움이 되는 사이트글의 목적
정규 표현식
을 이해하고 JavaScript에서의 다양한 사용법을 정리하기 위해 작성됐다.정규 표현식을 사용하면 문자열에서 특정 패턴을 찾고, 매칭 되는 것들을 배열로 받는 등 문자열 처리를 매우 편하게 할 수 있다. 웹 사이트의 이메일, 패스워드의 유효성 검증에도 자주 사용된다.
알아두면 손해는 안 보는 정규 표현식!
정규 표현식 객체(RegExp)의 메서드와 String 메서드, 다양한 예제로 정규 표현식을 이해해보자. 🔥
정규 표현식이 뭘까?정규 표현식(Regular Expression(RegExp, Regex), 정규식)은 문자열에서 특정 내용을 매칭 하는 데 사용된다.
다양한 프로그래밍 언어에서 문자열 검색과 치환을 위해 지원하고 있다. 언어마다 사용되는 메서드들은 차이가 있지만, 정해진 문법과 규칙(표현식 중간에 개행(줄 바꿈)을 해서는 안됨 등)이 존재한다.
/ 찾고자하는 패턴 / 플래그
형식으로 표현될 수 있다.Groups and ranges
|
또는 ( )
그룹 [ ]
괄호안의 어떤 문자 [^]
괄호안의 어떤 문자가 아닐 때 (?:)
: 뒤의 문자를 찾지만 그룹으로 만들지는 않음 (?<name>)
name이란 이름을 가진 그룹을 만듦 위의 문법들은 그룹화하거나 내부에 지정된 문자열의 범위를 다룬다.
Group : ( ) ?
( 패턴 ) 같이 ( ) 안에 찾고자 하는 패턴을 입력한 다면, 해당 패턴을 그룹으로 처리한다는 것을 의미한다.
정규 표현식을 /(young)|(ju)/gm으로 작성한다면, 첫 번째 그룹은 young, 두 번째 그룹은 ju가 된다.
( ) 로 묶은 그룹은 RegExp.$그룹번호로 접근하여 가져오거나, (?<name>)으로 이름을 만들어 준 후 해당 이름으로 접근한다. (groups.name)
Named capturing group 예시 👇간단한 예제로 위의 문법들을 익혀보자.
/(Hi|Hello)/
: Hi 또는 Hello/gr[aed]y/
: gray, grey, grdy/gr[^aed]y/
: gray, grey, grdy를 제외한 gr*y (*는 a,e,d를 제외한 모든 한 자리 문자)/gr[a-f]y/
: a부터 f까지. (gray, grby, grcy, grdy, grey, grfy)/[a-zA-Z]/
: 소문자 a~z, 대문자 A~Z까지에 포함되는 한 자리 문자
Quantifiers
?
없거나 있거나 (zero or one) *
없거나 있거나 많거나 (zero or more) +
하나 또는 많이 (one or more) {n}
n번 반복 {min,}
최소 min 이상 {min,max}
최소 min 이상 최대 max 이하 수량에 관련된 문법들이다.
/gra?y/
: a가 있거나 없을 때 매치. (gray, gry)/gra*y/
: a가 있거나 없거나 여러 개 있는 경우 매치. (gray, gry, graa...ay)/gra+y/
: a가 하나 있거나 여러 개 있는 경우 매치. (gray, graa...ay)/gra{2}y/
: a가 2번 나타나는 경우 매치. (graay)/gra{2,}y/
: a가 2번 이상 나타나는 경우 매치./gra{2,5}y/
: a가 2번 이상 5번 이하 나타나는 경우 매치. (graay, graaay, graaaay, graaaaay)
다음 문법으로 들어가기 전, 정규표현식의
플래그(Flags)
에 대해 알아보자.Flags
정규 표현식은 선택적으로 사용할 수 있는 플래그 g, i, m, u, s, y가 존재한다.
- g(global) : 매치되는 모든 문자(전역 검색). g 플래그가 없는 경우, 최초 검색만을 반환한다.
- i(case insensitive) : 대소문자 무시하고 매치.
- m(multiline) : 여러 줄을 구분하여 매치. 줄 별로 대응된다.
- u(unicode) : 유니코드 문자를 검색한다. \p{...} 를 이용해 유니코드 프로퍼티 검색 가능.
- s(single line, dotall) : dot(.)가 함께 사용되며, 개행 문자 \n를 포함시킨다. (원래 포함 X)
- y(sticky) : 문자 내 매칭 범위를 제한시켜 진행할 수 있게 된다.
💡
플래그들은 /gm, /gsi 처럼 중첩하여 사용 가능하다.Boundary-type
\b
단어 경계 \B
단어 경계가 아님 ^
문장의 시작 $
문장의 끝 /Young\b/gm
: Young으로 끝나는 단어에 매치.
/\bYoung/gm
: Young으로 시작하는 단어에 매치.
/Young\B/gm
: Young으로 끝나지 않는 단어에 매치.
/^Young/gm
: 문장에서 시작하는 Young을 선택.
/Young$/gm
: 문장의 끝의 Young을 선택. multiline 플래그가 없을 시 모든 문장을 포함한 끝에 Young이 있어야 매치된다.
Character classes
\
특수 문자가 아닌 문자 .
어떤 글자(개행문자 제외) \d
digit 숫자(0-9) \D
digit 숫자가 아닌 것 \w
word 문자 \W
word 문자가 아닌 것 \s
space 공백 \S
space 공백이 아닌 것 /./gm
: 모든 문자 매칭(개행 문자 제외)
/\./gm
: 특수문자 . 이 아닌 문자 .를 매칭. 그 외의?
,[
,]
등도 모두 역슬래시(\)로 문자를 찾는다고 표시를 해줘야 한다.
/\d/gm
: 숫자를 찾는다.
/\D/gm
: 숫자가 아닌 모든 것.
/\w/gm
: 모든 문자를 찾음.
/\W/gm
: 문자가 아닌 것들을 찾음.
/\s/gm
: space 공백을 찾음.
in JavaScriptJavaScript에서 정규 표현식은 객체이다.
RegExp 객체의 생성자로 호출이 가능하며, 정규 표현식 리터럴로 선언할 수도 있다.
const REGEX = /wow/; //정규 표현식 리터럴. 슬래시로 패턴을 감싼다. const REGEX2 = /wow/gm; //플래그가 있는 경우. // 이렇게 선언할 수도 있다. const REGEX = new RegExp('wow'); const REGEX2 = new RegExp('wow','gm');
RegExp의 내부 인스턴스 메서드에서 자주 쓰이는 메서드는 다음과 같다.
- RegExp.prototype.exec() : 문자열 매개변수에 대해 검색 실행. 수행 결과를 배열 혹은 null로 반환.
- RegExp.prototype.test() : 문자열 매개변수에 대해 판별한다. true혹은 false가 리턴된다.
그 외 조합해서 자주 사용되는 메서드들은 다음과 같다.
- String.prototype.replace() : 어떤 패턴에 일치하는 일부 또는 모든 부분이 교체된 문자열을 반환한다. (원래 문자열은 변경❌) global 플래그로 정규 표현식을 작성하면 replaceAll처럼 사용할 수 있다.
- String.prototype.match() : 문자열이 정규식과 매치되는 부분을 검색한다.
- String.prototype.split() : 지정한 구분자를 이용해 여러 개의 문자열로 나눈다.
응용 모음응용 1. 아래 사진을 참고하여 전화번호를 찾는 정규 표현식을 작성해보자.
응용 2. 아래 사진을 참고하여 유튜브 링크를 찾는 정규 표현식을 작성해보자. 유튜브 영상 ID는 11자리이다.
응용 3. 뉴스 클러스터링 문제 - 문자열 "FRANCE"를 두 글자씩 끊어 집합을 만든다. 두 글자씩 끊어진 원소는 모두 영문자로 되어 있어야 하며, 대소문자는 구분하지 않는다. 파라미터로 전해진 str를 두 글자씩 끊어 배열에 담아 리턴해주는
makeSplitArr
함수가 있을 때, const REGEX를 완성해보자!function makeSplitArr(str){ const array = []; for(let i=0;i<str.length-1;i++){ const lowerStr = str.slice(i,i+2).toLowerCase(); const REGEX = 퀴즈! ; //여기!!! REGEX.test(lowerStr) && array.push(lowerStr); } return array; } function solution(str1, str2){ //str1 = "FRANCE" const arr1 = makeSplitArr(str1); // arr1 = ["FR","RA","AN","NC","CE"]가 되어야 한다. // ... }
응용 4. 튜플 문제 - 주어진 s = "{{2},{2,1},{2,1,3},{2,1,3,4}}"를 [[2],[2,1],[2,1,3],[2,1,3,4]]로 변환해보자. 어떤 정규식, 어떤 메서드를 사용하면 s를 편하게 바꿀 수 있을까?
응용 5. 신규 아이디 추천 문제 5단계 - [new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.] 어떤 정규식, 어떤 메서드를 사용하면 new_id가 빈 문자열이라면 "a"를 대입할 수 있을까?
응용 6. 다트 게임 문제 - 0점부터 10점까지의 점수가 존재한다. dartResult는 점수|보너스|옵션 형식으로 주어지므로 점수로 문자열을 분리해주면 각 기회를 분리할 수 있을 것 같다. 어떤 정규식, 어떤 메서드를 사용하면 될까?
👇 응용 1 - 응용 6의 정답 중 하나(답은 여러 개가 될 수 있음.)
더보기응용 1.
/\d{2,3}[ -.]\d{3}[ -.]\d{4}/gm
응용 2.
/(https?:\/\/)?(www\.)?youtu.be\/([a-zA-Z0-9-]{11})/gm
응용 3.
/[a-z]{2}/
응용 4.
s.replace(/{/g,"[").replace(/}/g,"]")
응용 5.
new_id.replace(/^$/,"a")
응용 6.
dartResult.split(/(10|[0-9])/).slice(1)
// 순서가 바뀌면 안된다. /[0-9]|10/으로 작성시 10이 1로 먼저 분리됨.신규 아이디 추천 문제는 대표적인 정규 표현식 응용문제이다. 자신의 방법대로 풀어본 후, 다른 사람의 풀이도 둘러보며 다양한 정규 표현식 작성 방법을 보는 것도 도움이 많이 된다!
그 외에도 카카오 코딩 테스트 문제 난이도 Lv.1 문자열 관련 문제에는 정규 표현식을 사용하면 편하게 풀 수 있는 문제들이 많이 나오는 것 같다.
시간 복잡도정규 표현식은 일반적으로
백트래킹
(완전 탐색 알고리즘 기법)으로 일치 여부를 판단한다. 백트래킹은 최악의 경우 O(2^n)의 시간 복잡도를 가질 수 있다(n = 정규식 크기). 문자열 매칭 알고리즘 중 하나인 KMP는 시간 복잡도가 O(N(문자열 길이)+M(패턴 길이))으로 매우 효율적이나, 구현과 이해가 복잡하다.어디까지나 최악의 경우이므로, 정규식을 테스트하며 문제 발생 여부를 검증하며 진행한다면 문제는 대응할 수 있다. 알고리즘 문제의 경우 까다로운 문제가 아니라면 정규 표현식을 사용해도 큰 문제(시간 초과)는 발생하지 않는다.
학습에 도움이 되는 사이트시각적으로 이해하는 데 도움이 되는 RegExr
정규 표현식을 작성하면 아래 작성된 Text에서 매치되는 글자를 찾아주고, Explain에서 간단한 해설도 제공한다.
다양한 문제를 풀어볼 수 있는 RegexOne
정규 표현식에 대한 다양한 문제를 풀어볼 수 있다.
참고자료
https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Regular_Expressions