정규표현식 알아보기

2021-09-19

정규표현식(Regular Expression)은 일정한 패턴을 가진 문자열의 집할을 표현하기 위해 사용하는 형식 언어(Formal Language: 특정 법칙에 따라 적절하게 구성된 문자열들의 집합)다.

쉽게 말해, 내가 작성한 값이 어떠한 패턴을 준수하고 있는지를 알려준다. 주로 이메일, 비밀번호, 휴대폰번호 등의 패턴이 맞는지 확인할 때 사용한다.

ECMAScript 262에서도 정규표현식 객체를 정의하고 있으며, 정규표현식 리터럴과 RegExp 생성자 함수로 생성할 수 있다.

// 1. 정규표현식 리터럴
const regex = /hi/g

// 2. RegExp 생성자 함수
const regex = new RegExp('hi', 'g')

일반적으로 자주 사용되는 방법은 정규표현식 리터럴이며, 아래 그림과 같이 구성되어 있다.

정규표현식 리터럴

https://poiemaweb.com/js-regexp


정규표현식은 RegEx Tester, regex101, RegExr 등에서 테스트해 볼 수 있다.

플래그

정규표현식의 플래그는 총 여섯 개가 있으며 검색 방식을 정할 수 있다. 선택적으로 사용할 수 있으며, 순서 구분은 따로 없으며, 하나 이상의 플래그도 사용할 있다.

만약 아무것도 설정하지 않는다면 대소문자를 구별하며, 첫 번째 매칭 대상만 검색한다.

gGlobal모든 문자열(전역) 검색
iIgnore case대소문자 구분 없이 검색
mMulti-line여러 행 검색
sdotAll`.`에 개행 문자도 매칭(ES2018)
uUnicode유티코드, 패턴을 유니코드로 취급
yStickysticky 검색 수행, 문자열의 현재 위치부터 검색 수행

가장 자주 사용하는 플래그는 g, i, m 이 세가지다.

정규표현식 메서드

정규표현식에서 주로 사용되는 메서드는 RegExp.prototype.exec, RegExp.prototype.test, String.prototype.match다.

RegExp.prototype.exec

exec 메서드는 문자열을 검색하여 매칭 결과를 배열로 반환한다. 만약 매칭되는 것이 없으면 null을 반환한다.

const regExp = /hi/

const target = 'hi howdy-mj'
regExp.exec(target) // output: ['hi', index: 0, input: 'hi howdy-mj, Hi!', groups: undefined]

const noTarget = 'howdy-mj'
regExp.exec(noTarget) // output: null

또한, exec 메서드는 플래그를 g로 설정하더라도 첫 번째 타겟만 반환한다.

const regExp = /hi/
const hasTwoTarget = 'hi howdy-mj, hi!'
regExp.exec(hasTwoTarget) // output: ['hi', index: 0, input: 'hi howdy-mj, Hi!', groups: undefined]

const regExpWithG = /hi/g
regExpWithG.exec(hasTwoTarget) // output: ['hi', index: 0, input: 'hi howdy-mj, Hi!', groups: undefined]

RegExp.prototype.test

test 메서드는 문자열을 검색하여 매칠 결과를 boolean 값으로 반환한다. 회원가입 시 입력한 값이 설정한 패턴과 부합한지 알아보기 위해 주로 사용하는 메서드다.

const regExp = /hi/

const target = 'hi howdy-mj'
regExp.test(target) // output: true

const noTarget = 'howdy-mj'
regExp.test(noTarget) // output: false

String.prototype.match

match 메서드는 String 표준 빌트인 객체에서 제공하며, 정규 표현식과 매칠 경과를 배열로 반환하며 exec 메서드와 비슷하다. 다만, g 플래그를 사용할 경우, 모든 매칭 결과를 배열로 반환한다.

const regExp = /hi/
const hasTwoTarget = 'hi howdy-mj, hi!'
hasTwoTarget.match(regExp) // output: ['hi']

const regExpWithG = /hi/g
hasTwoTarget.match(regExpWithG) // output: ['hi', 'hi']

이 외, String.prototype.search, String.prototype.replace, String.prototype.split 메서드도 자주 사용된다.

특수문자로 패턴 만들기

위의 /hi/처럼 정규표현식을 만들 수 있지만, 휴대폰번호를 찾기 위해 01*-부터 모든 번호를 다 입력할 수 없다. 따라서 휴대폰 번호와 부합한 특정 패턴을 입력해야하는데, 이때 특수 문자를 사용해 그 패턴을 정의할 수 있다.

밑의 예시는 편의상 모두 플래그를 작성하지 않았다

시작 문자

^로 찾을 수 있다.

const startWithZeroRegExp = /^0/
const str = '010-1234-1234'
startWithZeroRegExp.test(str) // output: true

마지막 문자

$로 찾을 수 있다.

const endWithZeroRegExp = /0$/
const str1 = '010-1234-1234'
const str2 = '010-1234-1230'
endWithZeroRegExp.test(str1) // output: false
endWithZeroRegExp.test(str2) // output: true

반복 패턴

{m,n}은 최소 m번, 최대 n번이 반복되는 문자열을 뜻한다. 이때 m과 n사이에 띄어쓰기가 있으면 안되며, 둘 다 양인 정수로, m <= n 조건을 만족해야 한다. 만약 m이 생략된다면 m은 무한으로 취급된다. 만약 {n}만 존재한다면, n번의 문자열을 찾는다.

0회 이상 연속 반복

*로 찾을 수 있으며 {0,}과 같다.

const repeatYRegExp = /y*/
const str1 = 'yes'
const str2 = 'es'
repeatYRegExp.test(str1) // output: true
repeatYRegExp.test(str2) // output: true

1회 이상 연속 반복

+로 찾을 수 있으며, {1,}과 같다.

const repeatYRegExp = /y+/
const str1 = 'yes'
const str2 = 'yyes'
repeatYRegExp.test(str1) // output: true
repeatYRegExp.test(str2) // output: true

최대 한 번 반복

?로 찾을 수 있으며, {0,1}과 같다.

const repeatYRegExp = /y?/
const str1 = 'yes'
const str2 = 'es'
repeatYRegExp.test(str1) // output: true
repeatYRegExp.test(str2) // output: true

개행 문자를 제외한 단일 문자

.로 찾을 수 있다.

const secondORegExp = /.o/
const str1 = 'oh'
const str2 = 'socket'
secondORegExp.test(str1) // output: false
secondORegExp.test(str2) // output: true

문자열 검색

[xyz]로 설정할 수 있으며, [ ] 안의 문자는 or(|)와 동일하게 작동한다.

// 1. 영어 대/소문자
const lowerCaseRegExp = /[a-z]/
const upperCaseRegExp = /[A-Z]/

const lowerCase = 'test'
const upperCase = 'TEST'
const test = 'Test'

lowerCaseRegExp.test(lowerCase) // output: true
lowerCaseRegExp.test(upperCase) // output: false

lowerCaseRegExp.test(test) // output: true
upperCaseRegExp.test(test) // output: true

// 2. 숫자
const numberRegExp = /[0-9]/

const onlyNumber = '20210918'
const numberWithString = 'Covid19'

numberRegExp.test(onlyNumber) // output: true
numberRegExp.test(numberWithString) // output: true

[]은 위에 설명 된 ^, *, +와도 같이 사용될 수 있다.

단, []내의 ^은 해당 패턴으로 이루어진 문자열을 제외한 것을 의미한다.

const expectNumberRegExp = /[^0-9]/

const onlyNumber = '20210918'
const numberWithString = 'Covid19'

// 숫자로만 이루어진 것에 대해 false를 반환
expectNumberRegExp.test(onlyNumber) // output: false
expectNumberRegExp.test(numberWithString) // output: true

간략한 패턴 표현 방식

위와 같이 [] 내에 패턴을 작성하는 방법도 있지만, 더 간소한 형식도 있다.

\d숫자[0-9]
\D숫자가 아닌 것[^0-9]
\n줄 바꿈 (U+000A)
\s스페이스, 탭, 줄 바꿈 등을 포함한 하나의 공백[ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff].
\S공백이 아닌 것[^ \f\n\r\t\v\u00a0\u1680\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff].
\w밑줄(_)을 포함한 영문자, 숫자[A-Za-z0-9_]
\W밑줄(_), 영문자, 숫자가 아닌 것[^A-Za-z0-9_]

자주 사용하는 정규표현식

이메일

const emailRegExp = /^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/

비밀번호

// 1. 특수문자가 없는 8-20자리 비밀번호
const passwordRegExp = /[A-Za-z0-9]{8,20}/

// 2. 특수문자가 포함된 8-20자리 비밀번호
const passwordRegExp = /^.*(?=^.{8,20}$)(?=.*\W).*$/

// 3. 영어 대문자, 소문자, 숫자, 특수문자 각 1개가 포함된 8-20자리 비밀번호
const passwordRegExp = /^.*(?=^.{8,20}$)(?=.*\d)(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).*$/

핸드폰

// 1. 헨드폰 번호 (ex. 010123401234)
const phoneRegExp = /^01\d{7,8}/

// 2. -를 갖고 있는 핸드폰 번호 (ex. 010-123-1234)
const phoneWithDashRegExp = /^\d{3}-\d{3,4}-\d{4}/

// 3. 지역번호를 포함한 연락처 (ex. 02-1234-1234)
const contactNumber = /^\d{2,3}-\d{3,4}-\d{4}/

기타

// 숫자로만 이루어진 패턴
const onlyNumberRegExp = /^\d+$/

// 영문자로만 이루어진 패턴
const onlyAlphabetRegExp = /^[a-zA-Z]+$/

// 특수문자로만 이루어진 패턴
const symbolRegExp = /[^a-zA-Z0-9]/

// 특정 확장자 파일 (ex. tx, tsx, js, jsx 확장자)
const fileTypeRegExp = /^[\S]+\.(ts|tsx|js|jsx)$/

참고