정규표현(Regular Expression)이란?
숫자와 문자, 특수문자가 섞여 있는 문자열에서 특정 문자열 패턴을 표현할 수 있는 기법이 정규표현이다.
예를 들어서 우편 번호는 [0~9의 숫자 3행] + [-] + [0~9의 숫자 3행]의 패턴을 나타내는데, 이를 정규표현으로하면 다음과 같다.
[0-9]{3}-[0-9]{3}
이것을 지정하여 원래의 문자열과 비교함으로써 임의의 문자열에서부터 특정 패턴을 지닌 문자열을 검색하는 것이 가능하다.
JavaScript에서 가능한 정규표현
정규표현으로 이용 가능한 주요 문자열 패턴들 중 중요한 몇가지들이다.
분류 | 패턴 | 매칭하는 문자열 |
기본 | ABC | [ABC]라는 문자열 |
| [ABC] | A,B,C 중 한 개의 문자 |
| [^ABC] | A,B,C이외의 한 개의 문자 |
| [A-Z] | A~Z 사이의 한 문자 |
| A|B|C | A,B,C 중에서 어떤 것 |
양 지정 | X* | 0문자 이외의 X("fe*"는 "f", "fe", "fee"등으로 매치) |
| X? | 0 또는 1문자의 X("fe?"는 "f", "fe"에 매치, "fee"는 매치하지 않음 |
| X+ | 1문자 이상의 X("fe+"는 "fe", "fee" 등은 매치, "f"는 매치하지 않음) |
위의 표를 이용하여 URL을 나타내는 정규표현 패턴을 풀어보자.
http(s)?://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?
처음의 http(s)?:// 라는 문자열 안에 s가 0 또는 1회 등장한다는 표현이다. 즉, URL 문자열이 'http://' 또는 'https://'로 시작되는 것을 나타낸다.
([w-]+\.)+[\w-]+는 영숫자, 언더스코어, 하이픈으로 구성되는 문자열이며 도중에 피리어드(.)를 포함하는 것을 나타낸다.
(/[\w-./?%&=]*)?는 후속 문자열이 영숫자, 언더스코어, 하이픈, 슬래쉬, 피리어드, 그 외 특수문자를 포함한 문자로 구성될 수 있음을 나타낸다.
이것은 기본적인 URL의 표기를 매칭하는 정규표현이다.
RegExp Object를 생성하는 방법
RegExp를 생성하는 방법은 크게 두 가지이다.
1. RegExp객체의 생성자를 경유
2. 정규표현 literal 이용하기
var 변수명 = new RegExp('정규표현', '옵션'); // 생성자
var 변수명 = /정규표현/옵션; // literal
정규표현 literal에서는 정규표현 전체를 slash로 감싸지 않으면 안 된다는 점에 주의가 필요하다.
옵션의 경우는 아래와 같은 값을 지정할 수 있다.(복수의 경우 'gi'와 같이 나열해서 기술)
옵션 | 개요 |
g | 문자열 전체에 대해 매치하는가 |
i | 대소문자 구분하는가 |
m | 복수행에 대응하는가 |
위를 근거로 한 URL 문자열에 매칭하는 RegExp object를 생성하면 다음과 같다.
var p = new RegExp('http(s)?;//([\\w-]+\\.)+[\\w-]+(/[\\w-./?%&=]*)?', 'gi');
var p = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?/gi;
이 둘은 두 가지 차이가 있다.
1. 생성자 클래스 구문에서는 \를 이스케이프 할 것.
생성자 구문에서는 정규표현이 문자열로서 지정되어 있다. JavaScript의 문자열 literal에 있어서 \는 의미를 지닌 예약어이다.
따라서 본래의 정규표현 패턴인 \w로서 인식시키기 위해서는 \를 \\로서 이스케이프 해야 한다.
2. 정규표현 literal에서는 /를 이스케이프 할 것.
정규표현 literal에서는 /가 패턴의 시작과 종료를 나타내는 예약어이다. 따라서 정규표현 자체에 /를 포함한 경우에는 \/와 같이 이스케이프처리해줘야 한다.
RegExp에 의한 검색의 기본
정규표현으로 검색하려면 String.match method를 이용한다.
var p = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?/gi;
var str = '서포트 사이트는 http://www.wings.msn.to/입니다.';
str += '샘플소개사이트 HTTP://www.web-deli.com/도 잘 부탁합니다!';
var result = str.match(p);
for(var i = 0; i < result.length; i++) {
document.writeln(result [i]);
}
이 결과로는 result[0]에 첫째 URL이 들어가고 result[1]에 둘째 URL이 들어가게 된다.
위에서는 옵션을 'gi'로 가져가고 있기 때문에 대소문자 구분이 없이 두 URL 모두 검색했다. 그러나 각각을 제외했을 때 결과는 테스트 해보면 쉽게 알 수 있다.
약간 어려운 옵션이 m(멀티라인 모드)이다.
var p = /^[0-9]{1,}/g; // 문자열 선두에 있는 한 문자 이상의 숫자를 검색
var str = '101 마리의 강아지.\n7 명의 어린이';
var result = str.match(p);
for(var i = 0; i < result.length; i++) {
document.writeln(result[i]);
}
위 코드의 결과 값은 '101'이다. 위에는 g로 전체 문자열을 검색하지만 m(멀티라인 모드) 옵션을 주지 않았기 때문에 첫 줄에서 끝나고 101만 출력한다.
m을 합쳐서 'gm' 옵션을 준다면 당연히 결과는 101, 7 이 두 줄에 걸쳐 나온다.
match vs exec method
String.match method 이외에 RegExp.exec method를 이용하는 방법도 있다.
var p = /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?/gi;
var str = '서포트 사이트는 http://www.wings.msn.to/입니다.';
str += '샘플소개사이트 HTTP://www.web-deli.com/도 잘 부탁합니다!';
var result = p.exec(str);
for(var i = 0; i < result.length; i++) {
document.writeln(result [i]);
}
위 코드의 결과는 이전과는 좀 다르다.
http://www.wings.msn.to/
msn.
/
이렇게 나오는 이유는 exec method가 한 번의 실행에 하나의 실행 결과만을 돌려주기 때문이다.
이 문자열을 모두 매치하기 위해서는 for 문 대신에 while((result = p.exec(str)) != null)으로 반복시켜주면 된다.
왜냐하면 exec method는 마지막에 매치한 문자 위치를 기억하는 기능을 가지고 있기 때문이다.
그리고 다음 번에 exec method가 실행될 때는 RegExp object는 이전의 매치 위치로부터 검색을 재개한다. 그리고 마지막에 다음 검색 결과가 없는 경우는 null을 반환한다.
Match 정보 획득하기
RegExp object는 exec method로 매치 정보를 참조하기 위한 몇 가지 property를 공개하고 있다.
property | alias | 개요 |
lastIndex | - | 검색을 개시하는 위치 |
leftContext | $` | 마지막 매치열의 앞 문자열 |
rightContext | $' | 마지막 매치열의 뒤로 계속 되는 문자열 |
lastMatch | $& | 마지막에 매치한 문자열 |
lastParen | $+ | 마지막에 매치한 ()로 둘러싼 그룹의 문자열 |
$1~9 | - | 패턴 매치한 문자열을 순서대로 보관(최대 9개) |
lastIndex를 제외하고는 전부 static property이다.
alias는 각각의 property를 참조하기 위한 별명키다. 예를 들어서 RegExp.lastMatch 는 RegExp.['$&']와 같이 바꿔 써도 무방하다.
위 정보 외에 매치의 성공 여부를 확인해보기 위해서는 test method를 쓰면 된다.
test method는 주어진 문자열을 검색해 그 결과값을 true/false로 반환해준다.
RegExp로 문자열 치환/분할 하기
String.replace method를 이용해서 문자열을 치환할 수도 있다.
var p = /(http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?)/gi;
var str = '서포트 사이트는 http://www.wings.msn.to/입니다.';
document.writeln(str.replace(p, '$1'));
위 코드는 문자열에 포함된 URL 문자열을 Anchor tag로 치환하는 코드다.
URL부분이 하이퍼링크가 걸려서 브라우저 창에 표현된다.
$1~$9라는 특수 변수를 내장해서 각 서브 매치 문자열들을 보존할 수 있게 한다. 위의 코드의 경우에는 $1에 URL이 들어가게 되는 셈.
RegExp로 문자열을 분할하려면 String.split method를 사용한다.
var p = /[\/\.\-]/gi;
document.writeln('2010/12/04'.split(p)); // 2010,12,04
document.writeln('2010-12-04'.split(p)); // 2010,12,04
document.writeln('2010.12.04'.split(p)); // 2010,12,04
단락 문자가 /, -, . 중 어느 하나에 해당한다면 문자열이 올바르게 분할이 된다.
split method는 반환값으로 분할한 결과를 배열로 반환한다. (배열을 write method로 출력하게 되면 콤마 단락의 문자열이 반환된다.)