본문 바로가기
JavaScript

정규표현식(Regular Expression)

by enai 2019. 8. 22.

정규표현식은 문자열의 특정 패턴을 찾을 수 있는 문법을 말한다.

정규표현식을 이용해 패턴에 맞는 문자열을 추출, 삭제, 치환 등 조작 할 수 있다.

 

보통 이메일, 주소, 전화번호 같은 일정한 규칙이 있는 데이터가 그 규칙에 맞는지 검증하고,

textarea에 입력된 것 중 불필요한 입력값을 추출하고, 트랜스파일링, 개발 도구에서의 문자열 치환 등에 쓰인다.

(트랜스파일링은 예전 버전의 브라우저를 지원하기 위해 해당 브라우저에 맞는 문법으로 변환시켜주는 것을 말한다.

개발 도구에서의 문자열 치환은 개발 도구에서 코드의 어떤 부분을 치환한다는 의미로 쓰여졌다.)

 

 

 

1. 정규표현식 기본 사용법

 

1) 숫자 하나 찾기

var result = "abc3zzz".match(/\d/)[0];

console.log(result); //결과 값: 3

 

2) 숫자 두 개 찾기

var result = "abc32zzz".match(/\d\d/)[0];

console.log(result); //결과 값: 32

 

match 메서드로 정규표현식에 맞는 문자열을 찾아낸다.

정규표현식은 // 사이에 입력한다. \d는 숫자 하나를 뜻한다. (\ = 역슬래쉬)

 

[0]은 match 메서드 결과가

[ '3', index: 3, input: 'abc3zzz', groups: undefined ]

이런 배열로 나오기 때문이다. 원하는 값은 0번째 인덱스에 있으므로 [0]을 붙여준다.

 

javascript regex cheat sheet를 검색해서 정규표현식에 대한 패턴들을 알 수 있다.

JavaScript Regex Cheatsheet

Regular Expressions - github

등등... 구글링으로 여러 자료를 찾을 수 있다.

 

 

 

 

2. 정규표현식 예제

 

1) 구/신 우편번호

var newZipCode = "19323".match(/(\d{3}-\d{3}|\d{5})/)[0];
console.log (newZipCode); //결과 값: 19323

var zipCode = "193-123".match(/(\d{3}-\d{3}|\d{5})/)[0];
console.log (zipCode); //결과 값: 193-123

 

\d{3}은 \d\d\d와 같다. {}는 앞의 정규표현식의 개수를 표시한다.

이렇게 괄호를 묶어 어떤 블록 영역을 지정하는 표현식을 하위 표현식(sub expression)이라고 한다.

 

|는 or을 뜻한다.

그래서 위 코드는 숫자 3자리 - 숫자 3자리 형태이거나 숫자가 5자리 형태인 문자열만 추출해낸다.

(match가 정규표현식에 대응되는 문자열을 반환해주는 메서드이다. 대응되는 문자열이 없으면 null을 반환한다.)

 

 

2) 핸드폰 전화번호

var phoneNumber = "010-9021-0011".match(/01[01789]-\d{3,4}-\d{4}/)[0];

 

[01789]: 안의 숫자들 중 하나

\d{3,4}: 3~4자리의 숫자 (자릿수 지정하는 것을 수량자라고 한다.)

 

그래서 전화번호 시작이 010, 011, 017, 018, 019이고, - 다음 숫자가 3자리 혹은 4자리 - 다음에 숫자 4자리가 되는 문자열이 추출된다.

 

 

3) 개발도구에서 함수 선택하기

개발도구에서 정규표현식으로 해당하는 내용을 검색할 수 있다.

함수를 찾으려면 다음과 같은 정규표현식을 사용할 수 있다.

\(?function\s+[a-zA-Z_$]+

 

\(: 정규표현식에서 '('는 메타 문자이다. 문자 그대로의 '('를 표현하기 위해서 앞에 \를 붙인다.

?: 하나가 있거나 없거나

\s: 공백

+: 하나 이상 ({1,}이라고 해도 된다)

\w: 문자 (대소문자 상관없이 a부터 z까지, _언더바까지 포함한 문자)

[a-zA-Z_$]+: a부터 z, A부터 Z, _와 $까지 범위의 문자가 하나 이상

 

그래서 function이 들어간 함수를 찾아낼 수 있다.

 

이 외에도 이런 식으로 var, const, let 등의 변수만 추출해올 수도 있고, 다양한 활용이 가능하다.

 

var 타입의 변수는

\s?var\s[$_a-zA-Z]+

이렇게 찾을 수 있을 것이다.

위의 예제를 vscode에서 찾는다면 아래와 같이 하면 된다.

 

정규표현식으로 찾아낼 파일을 열고,

ctrl+f로 검색창을 연다.

검색창 옆의 Use Regular Expression 버튼(사진 속 파란색으로 된 버튼)을 클릭하고, 정규표현식을 입력한다.

해당하는 문자열이 블록으로 잡히는 것을 확인할 수 있다.

 

 

4) 데이터 치환하기

만약 vscode에서 정규표현식을 이용하여 데이터를 치환하려면 바꾸기 창을 연다.

단축키는 ctrl+h이다.

역시 Use Regular Expression 버튼을 클릭하고 바꿔줄 데이터에 해당하는 정규표현식을 검색한다.

위 예제는 var를 const로 바꾸는 것이다.

(\s?)(var)(\s[$_a-zA-Z]+)

이렇게 구역을 나눠 괄호를 쳐준다. 괄호를 감싼 데이터를 $로 호출할 수 있다. 1부터 순서대로 숫자를 붙여 구분한다.

바꿀 내용으로 다음을 입력한다.

$1const$3

$1은 \s?이고, $3은 \s[$_a-zA-Z]+ 부분을 가리킨다.

모두 바꾸기를 선택하면 var 변수가 모두 const 타입으로 바뀌어져 있다.

 

replace 메서드로도 바꿀 수 있다.

var result = "011-021-0011".replace(/(\d{2})\d/, "$10");

console.log(result); //결과 값: 010-021-0011

replace 메서드는 첫번째 인수를 두번째 인수로 바꾸는 메서드이다.

두번째 인수 $10의 의미는 첫번재 인수의 첫번재 괄호 데이터와 그 뒤에 0을 붙인 데이터를 가리킨다.

 

 

5) 탐욕적(greedy), 게으른(lazy) 수량자

var love = "$$$iloveyou###".replace(/.*([a-zA-Z]+).*/, "$1");
console.log(love); //결과 값: u

.은 개행을 제외한 모든 문자, *은 0개 이상을 뜻한다.

$1로 바꾼다 했으니, 첫번째 괄호 데이터인 [a-zA-Z]+ 패턴에 맞는 데이터가 추출되어야 할 것이다.

처음 예상에는 console.log(love)의 결과가 iloveyou일 줄 알았지만, 실제 결과는 u가 출력되었다.

 

*가 최대한 많은 것을 찾으려고 하기 때문이다. 탐욕스럽게 끝까지 찾아간다.

그래서 *를 탐욕적 수량자라고 한다.

 

iloveyou를 찾고 싶다면 정규표현식을 다음과 같이 바꾸면 된다.

var love = "$$$iloveyou###".replace(/.*?([a-zA-Z]+).*/, "$1");
console.log(love); //결과 값: iloveyou

* 뒤에 ?가 추가되었다.

?는 게으른 수량자라고 한다.

뒤의 [a-zA-Z]+에 해당하는 값을 찾았으니 게으르게 더 이상 가지 않는 것이다.

 

 

탐욕적 수량자는 뒤에서부터 찾고, 게으른 수량자는 앞에서부터 찾는다고 생각하면 된다.

greedy: *, +, {n,}

lazy: *?, +?, {n,}?

 

 

 

 

3. 정규표현식과 함께 쓰이는 메서드들

 

1) 정규표현식에 맞는 문자열을 찾아주는 메서드

exec, match가 있다.

"Tel: 010-1234-1234"라는 문자열에서 휴대폰 전화번호를 찾아내는 예제로 각 메서드의 사용 방법을 알아보려고 한다.

 

- exec

var telRegex = /01[01789]-\d{3,4}-\d{4}/;

var phoneNumber = telRegex.exec("Tel: 010-1234-1234");
console.log(phoneNumber);

/* 결과 값
[ '010-1234-1234',
  index: 5,
  input: 'Tel: 010-1234-1234',
  groups: undefined ]
  */

exec 메서드는 정규표현식에 맞는 문자열에 대한 정보를 배열로 반환한다.

그래서 정규표현식에 맞는 문자열만 가져오기 위해선 다음과 같이 수정해야 한다.

var telRegex = /01[01789]-\d{3,4}-\d{4}/;

var phoneNumber = telRegex.exec("Tel: 010-1234-1234")[0];
console.log(phoneNumber); //결과 값: 010-1234-1234

exec가 반환하는 배열 중 첫번째 인덱스에 원하는 값이 있으므로, 0번 인덱스 값만 가져오도록 수정한다.

exec은 정규표현식에 맞는 문자열이 없다면 null을 반환한다. 그러므로 인덱스 번호로 특정 값만 가져오려고 할 때 오류가 날 수 있으므로 이 점을 주의해야 한다.

 

- match

var telRegex = /01[01789]-\d{3,4}-\d{4}/;

var phoneNumber = "Tel: 010-1234-1234".match(telRegex);
console.log(phoneNumber);

/* 결과 값
[ '010-1234-1234',
  index: 5,
  input: 'Tel: 010-1234-1234',
  groups: undefined ]
  */

match 메서드 역시 정규표현식에 맞는 문자열에 대한 정보를 배열로 반환한다.

exec와 같은 기능을 하지만, 문자열과 정규표현식의 위치가 다르다.

또한 위 결과 값에서 알 수 있듯이 원하는 정보는 010-1234-1234이므로

var telRegex = /01[01789]-\d{3,4}-\d{4}/;

var phoneNumber = "Tel: 010-1234-1234".match(telRegex)[0];
console.log(phoneNumber); //결과 값: 010-1234-1234

배열의 첫번째 인덱스 값만 가져오도록 수정한다.

만약 정규표현식에 맞는 문자열이 없다면 null을 반환하므로 위 코드에 오류가 있을 수 있다는 것을 주의해야 한다.

 

 

2) 정규표현식에 맞는 문자열인지 검사하는 메서드

test, search

문자열에 휴대폰 전화번호가 있는지 확인하는 예제로 각 메서드의 사용 방법을 알아보려고 한다.

 

- test

var telRegex = /01[01789]-\d{3,4}-\d{4}/;

var phoneNumber = telRegex.test("Tel: 010-1234-1234");
console.log(phoneNumber); //결과 값: true

test는 검사해주는 메서드인 만큼, 정규표현식에 맞는 값이 있으면 true, 없으면 false를 반환해준다.

위 예제는 맞는 문자열이 있으므로 true를 반환하였다.

 

- search

var telRegex = /01[01789]-\d{3,4}-\d{4}/;

var phoneNumber = "Tel: 010-1234-1234".search(telRegex);
console.log(phoneNumber); //결과 값: 5

search 메서드는 정규표현식에 대응되는 부분의 인덱스 번호를 반환한다. 없으면 -1을 반환한다.

반환하는 값이 -1이 아니면 정규표현식에 맞는 문자열이 있다고 생각하면 되겠다.

 

 

3) 정규표현식에 맞는 문자열을 다른 문자열로 바꿔주는 메서드

replace

"Tel: 010-1234-1234" 문자열에서 "Tel: "을 없애는 예제로 replace 메서드의 사용 방법을 알아보고자 한다.

 

- replace

var telRegex = /.*(01[01789]-\d{3,4}-\d{4})/;

var phoneNumber = "Tel: 010-1234-1234".replace(telRegex, "$1");
console.log(phoneNumber); //결과 값: 010-1234-1234

replace 메서드는 데이터 치환하기와 탐욕적 수량자 설명할 때 이미 나온 메서드이지만, 다시 한번 정리해보려고 한다.

인자는 두개를 받는다. 앞의 문자열에서 첫번째 인자로 받은 정규표현식에 맞는 문자열을 두번째 인자로 받은 문자열로 치환한다.

참고로 정규표현식을 괄호로 감싸면 $로 호출할 수 있다.

(정규표현식의 '.'이 개행문자를 제외한 모든 문자를 가리키므로, 뒤의 괄호로 쳐진 전화번호 정규표현식을 제외한 문자 전까지의 모든 문자가 .에 해당된다.)

$1로 바꾸겠다 했으니, 괄호 쳐진 전화번호 정규표현식에만 맞는 데이터로 바뀌게 된다.

 

(문자로 설명하려니 잘 설명되는 것인지 모르겠다. 코드를 보거나 직접 써보는 게 더 잘 이해가 될 것 같다.)

 

 

4) 정규표현식에 맞는 문자열을 기준으로 나눠서 배열로 만들어주는 메서드

split

"Tel: 010-1234-1234"을 전화번호 정규표현식을 기준으로 배열로 만들면 어떻게 될지 확인해보자.

 

- split

var telRegex = /01[01789]-[0-9]{3,4}-[0-9]{4}/;

var phoneNumber = "Tel: 010-1234-1234".split(telRegex);
console.log(phoneNumber);

//결과 값: [ 'Tel: ', '' ]

정규표현식이 전화번호를 가리키니까, split 메서드는 "010-1234-1234"를 기준으로 배열을 만들었다.

결과는 ['Tel: ', ''] 이런 배열이 나왔다.

 

 

 

출처)

edwith 부스트코스 웹 프로그래밍

- 정규표현식이란?

MDN - 정규표현식

 

 

댓글