티스토리 뷰

728x90
SMALL

정규 표현식은 문자의 패텬을 나타내는 객체다. 자스의 RegExp 클래스는 정규 표현식을 표현하고, String과 RegExp에는 정규 표현식을 사용하여 강력한 패턴 매칭을 수행하는 메서드와 텍스트상에서 특정 텍스트를 찾아서 바꾸는 함수가 정의되어 있다.

정규 표현식의 정의

자스에서 정규 표현식은 RegExp 객체로 표현된다. 물론 RegExp 객체는 RegExp() 생성자를 사용하여 만들어지지만, 생성자보다는 정규 표현식 리텉럴 문법이 더 자주 사용된다. 정규 표현식 리터럴은 한 쌍의 슬래시(/) 문자 사이에 위치한 문자들로 지정된다.

리터럴 문자

모든 영문자와 숫자는 그 문자 그대로 정규 표현식에서 매치된다. 알파벳이 아닌 문자들은 역슬래시로 시작하는 이스케이프 문자열을 통해 지원한다.

몇 가지 구두점 문자는 정규 표현식에서 특별한 의미를 가진다.(다음절에서...)

문자 클래스

문자 클래스

/[abc]/는 a,b,c 중 하나의 글자와 매치한다.

부정 문자 클래스

/[^abc]/는 a,b,c를 제외한 나머지 모든 문자와 매치한다.

문자 클래스는 문자의 범위를 지정하기 위해 하이픈(-)을 사용할 수 있다. 만약 라틴 알파벳 소문자와 매치되게 하려면 /[a-z]/를 사용하고, 모든 라틴 알파벳 글자나 숫자와 매치되게 하려면 /[a-zA-Z0-0]/을 사용한다.

반복

지금까지 배운 정규 표현식 문법을 사용하면 여러분은 두 자리 숫자를 /\d\d/로 표현할 수 있다. 그러나 임의 자리의 수 또는 세 개의 문자가 있고 뒤이어 생략 가능한 숫자로 이루어진 문자열을 표현하기는 어려울 것이다. 이런 식으로 더 복잡한 패턴은 정규 표현식의 요소가 몇 번이나 반복되는지를 나타내는 문법을 사용한다.

ex)

/\d{2,4}/          //두 자리에서 네 자리의 숫자와 매치된다.

/\w{3}\d?/       //정확히 세 개의 문자와 생략 가능한 숫자와 매치된다.

/\s+java\s+/    //java와 앞 뒤로 하나 이상의 공백 문자를  포함한 문자열과 매치된다.

/[^(]*/              //시작 괄호가 아닌 0개 이상의 문자와 매치된다.

*와 ? 반복 문자를 사용할 때는 조심해야 한다. 이 문자들은 그 앞에 오는 문자가 무엇이든 간에 0번 매치된다고 간주하기에, 반복 문자열 앞의 문자가 매치되지 않는 상황도 허용한다. 예를 들어 정규 표현식 /a*/는 실제로 문자열 "bbbb"와 매치되는데, 이는 이 문자열에 a가 0번 나타나기 때문이다.

비탐욕적 방법

탐욕적 : 반복 문자는 주어진 정규 표현식에 매칭되는 가능한 한 많은 문자와 매치된다.

이 반복을 비탐욕적으로 수행하게 지정할 수도 있는데 이는 반복 문자나 일반 문자 뒤에 물음표를 추가해주면 된다.

예를들어 정규 표현식 /a+/는 한 개 이상의 a와 매치되는데, 이 정규 표현식을 "aaa"에 적용하면 세 문자 모두와 매치한다. 그러나 /a+?/는 매칭에 필요한 a가 한 번 이상 나타나더라도, 최소한의 글자만 매칭한다. "aaa"에 이 정규 표현식을 적용하면 오직 첫 번째 글자 "a"만 매치된다.

비탐욕적 방법이 언제나 기대한 결과를 가져다주지는 않는다. /a+?b/ 패턴을 "aaab"에 적용했을 때 "ab"가 아닌 "aaab"가 나온다. 왜냐하면 문자열을 앞부분부터 탐색하다가 매치가 되면 정규 표현식 패턴 매칭이 완료되기 때문이다. 이 경우 문자열의 첫 번째 문자부터 매칭되기 때문에, 이후의 문자로부터 시작하는 더 짧은 매치는 전혀 고려되지 않는다.

대체, 그룹화, 참조

대체 표현식 : 파이프 문자(|)는 대체 표현식을 구분한다

/ab|cd|ef/는 문자열 "ab"또는 "cd"또는"ef"와 매치된다.

대체  표현식은 매치를 발견할 때 까지 왼쪽에서 오른쪽을 수행된다는 점을 염두.

정규 표현식에서 괄호는 여러 목적으로 사용된다. 하나는 분리된 항목을 하나의 부분 표현식으로 묶고(그룹화), 이렇게 묶인 항목들을 |, *, +, ? 등이 하나의 단위로 취급할 수 있도록 하는 것이다.

ex) /java(script)?/는 "java"와 그다음에 생략 가능한 "script"가 오는 문자열과 매치된다.

/(ab|cd)+|ef/ 는 "ab" 또는 "cd"가 한번 이상 반복되는 문자열 혹은 문자열 "ef"와 매치된다.

정규 표현식에서 괄호의 다른 목적은 전체 패턴 내의 부분 패턴을 정의하는 것이다. 정규 표현식이 대상 문자열에 대해 성공적으로 매치되면, 괄호로 둘러싸인 특정 부분의 패턴과 매치되는 부분 문자열을 추출할 수 있다.

ex) 한 개 이상의 소문자와 뒤따르는 한 자리 이상의 숫자를 찾는다고 가정하자. 이 경우 /[a-z]+\d+/ 패턴을 사용할 수 있다. 만약 각 매치에 대해 긑에 있는 숫자에만 관심이 있다고 가정하면, 패턴 일부를 (/[a-z]+(\d+)/)와 같이 괄호 안에 두고 찾아낸 매치 결과에서 숫자를 추출할 수 있다.

괄호로 둘러싸인 부분 표현식을 사용하면 같은 정규 표현식 내에서 해당 부분을 다시 참조할 수 있다. 이는 / 문자와 그 뒤에 숫자를 두면 되고, 이 숫자는 정규 표현식 내에서 괄호로 둘러싸인 부분 표현식의 위치를 나타낸다.

정규 표현식 내에서 부분 표현식에 대한 참조는 부분 표현식의 패턴을 참조하는 것이 아니라 패턴과 매치되는 텍스트를 참조한다. 따라서 문자열 내에서 서로 위치가 다른 문자들이 정확히 같은 문자를 포함하도록 제약을 할 때 참조를 사용할 수 있다.

ex) 다음 정규 표현식은 작은따옴표나 큰따옴표 사이에 한 개 이상의 문자가 있다면 매치된다. 그러나 처음 따옴표와 끝 따옴표가 매치될 필요는 없다. (즉, 두 따옴표 모두 작은 따옴표이거나 큰따옴표일 것을 요구하지 않는다.)

/['"][^'"]*['"]/

따옴표가 서로 매치되게 하려면 참조를 사용한다.

/(['"])[^'"]*\1/

\1은 첫 번째 괄호로 둘러싸인 부분 표현식이 매치된 텍스트에 매치된다. 이 예제에서 \1은 끝 따옴표가 처음 따옴표와 매치되도록 제약을 둔다. 이 정규 표현식은 작은따옴표가 큰따옴표 사이에 있거나 그 반대를 허용하지 않는다. 문자 클래스 내에서는 참조를 사용할 수 없기 때문에 다음과 같이 해서는 안된다.

/(['"])[^\1]*\1/

괄호로 둘러싸인 부분 표현식에 대한 이러한 종류의 참조는 곧 정규 표현식의 '검색 후 바꾸기'라는 강력한 기능이다.

번호로 지정된 참조 값 없이도 정규 표현식에서 항목을 그룹화할 수 있다. 그룹화를 하는 데 '('와 ')'를 사용하는 대신, '(?:'을 사용하여 그룹을 시작하고 ')'로 끝낸다

/([Jj]ava(?:[Ss]cript)?\sis\s(fun\w*)/

매치 위치 지정

정규 표현식 앵커 : 요소들이 검색할 문자열의 특정 위치에 정규식을 고정

일반적으로 가장 많이 사용하는 앵커 요소는 문자열의 시작 부분에 정규식을 고정하는 ^와 문자열의 마지막에 정규식을 고정하는 $이다.

임의의 정규 표현식을 앵커 조건으로 사용할 수 있다. 만약 '?='와 ')' 문자 사이에 표현식이 있으면 이는 긍정형 전방 탐색 선언문이고, 이는 '(?=?와 ')' 사이에 있는 문자들이 반드시 매치되어야 한다는 의미지만 실제로 자신의 매칭 결과를 반환하지는 않는다.

프로그래밍 언어(java, javascript 다음에 콜론이 따르는 경우를 매칭시키려면 /[Jj]ava([Ss]cript)?(?=\:)/을 사용할수있다. 

만약 '(?!'를 사용하여 선언문을 만들면, 이는 부정형 전방 탐색이고, 다음에 나오는 문자열들이 매치되면 안 된다.

/Java(?!Script)([A-Z]\w*)

플래그(flag)

정규 표현식 플래그는 고차원 패턴 매칭 규칙을 지정한다. 다른 정규 표현식 문법과는 달리 플래그는 /문자 바깥에 나타나며 두 번째 슬래시 다음에 지정된다. 

패턴 매칭을 위한 문자열 메서드

다음에 다루는 내용은 단지 정규 표현식과 관련된 여러 메스드와 프로퍼티에 대한 개요일 뿐이다. 완전한 내용은 3부에서...

문자열에는 정규 표현식을 사용하는 메서드 네 개가 있다. 가장 간단한 것은 search() 메서드다. 이 메서드는 정규 표현식을 인자로 받고, 가장 처음 매칭되는 부분 문자열의 위치를 반환한다. 만약 매칭되는 부분 문자열이 없다면 -1을 반환한다. 만약 search()에 넘기는 인자가 정규 표현식이 아니라면, 이 인자는 먼저 RegExp 생성자로 넘겨지고 정규 표현식으로 변환된다. search()는 전역 검색을 지원하지 않기 때문에, 정규 표현식 인자의 g 플래그는 무시된다.

ex) "JavaScript".search(/script/i);  4

replace() 메서드는 '검색 후 바꾸기'를 수행한다. 첫 번째 인자로는 정규 표현식을 받고, 두 번째 인자로는 교체할 문자열을 받는다. 만약 replace()의 첫 번째 인자가 정규 표현식이 아니라 일반 문자열이 전달되더라도, RegExp() 생성자를 사용하여 정규 표현식으로 변환하지 않고 전달된 문자열을 문자열 그대로 찾는다.

text.replace(/javascript/gi, "JavaScript");

//quote는 인용 부호와 인용 부호가 아닌 임의 개수의 문자
//그리고 인용 부호가 오는 정규 표현식이다.
var quote=/"([^"]*)"/g;
//인용 부호를 굽은 따옴표로 바꾼다.
//인용 부호 내의 텍스트($1에 저장된)는 바뀌지 않는다.
text.replace(quote, '"$1"');

 

다른 기능은 3부의 String.replace()에 설명. 가장 특별한 것은 replace()의 두번째 인자는 함수가 될 수 있다는 점이고, 이 함수는 교체될 문자열을 동적으로 계산한다.

String에서 정규 표현식을 사용하는 메서드 중 match() 메서드는 가장 일반적으로 사용된다. match() 메서드는 오직 정규 표현식 하나만을 인자로 받고, 매치 결과를 배열로 반환한다.

"1 plus 2 equals 3".match(/\d+/g)  //["1","2","3"]을 반환한다.

replace() 메서드와 마찬가지로 a[n]에는 $n의 내용이 저장되어 있다.

var url=/(\w+):\/\/([\w.+)\/(\S*)/;
var text="Visit my blog at http://www.example.com/~david";
var result=text.match(url);
if(result!=null){
  var fullurl=result[0];
  var protocol=result[1];
  var host=result[2];
  var path=result[3];
}

 

String 객체의 정규 표현식 메서드 중 마지막은 split()이다. 이 메서드는 주어진 인자를 구분자로 삼아, 메서드가 호출된 문자열을 부분 문자열로 쪼갠다.

"123,456,789".split(","); //["123","456","789"]을 반환한다.

split() 메서드 또한 정규 표현식을 인자로 받을 수 있다.

"1, 2, 3, 4, 5".split(/\s*,\s*/);    //["1", "2", "3", "4", "5"]를 반환한다.

RegExp 객체

정규 표현식은 RegExp 객체로 표현된다. RegExp() 생성자 왜에도 RegExp 객체는 세 가지 메서드와 몇 개의 프로퍼티를 지원한다.

RegExp() 생성자는 하나 또는 두 개의 문자열을 인자로 받고 새로운 RegExp() 객체를 생성한다. 이 생성자에 전달되는 첫 번째 인자는 정규 표현식의 본문이다. 두번째 인자는 생략할 수 있다. 만약 인자를 지정하면 이는 정규 표현식 플래그를 의미하고 g,i,m 또는 이 문자들의 조합이어야 한다.

//문자열에서 다섯 자리 숫자를 모두 찾는다. 역슬래시를 두 번 사용한 것을 주목하라

var zipcode=new RegExp("\\d{5}", "g");

RegExp 프로퍼티

RegExp 객체에는 다섯 개의 프로퍼티가 있다. source 프로퍼티는 정규 표현식의  텍스트를 저장한 읽기 전용 문자열이다. global 프로퍼티는 읽기 전용 불리언 값으로 정규 표현식에 g 플래그가 있는지를 나타낸다. ignoreCase 프로퍼티는 읽기 전용 불리언 값으로 정규 표현식이 i 플래그를 가지고 있는지 여부를 나타낸다. multiline 프로퍼티는 읽기 전용 값으로 정규 표현식에 m 플래그가 있는지를 나타낸다.마지막 lastIndex 프로퍼티는 읽고 쓸 수 있는 정수 값이다. g 플래그를 사용한 정규 표현식에 대해, lastIndex 프로퍼티는 문자열의 어느 위치에서 다음 검색이 시작되는지를 지정한다.

RegExp 메서드

RegExp 객체에는 패턴 매칭을 수행하는 두 메서드가 있고, 이 메서드는 앞에서 설명한 String의 메서드와 비슷하게 작동한다. 가장 중요한 메서드는 exec()이다. match()와 비슷한데, String의 match 메서드가 RegExp를 인자로 받는 것과 달리 RegExp 메서드는  문자열을 인자로받는다. exec() 메서드는 주어진 문자열에 대해 정규 표현식을 실행 시킨다. 즉, 주어진 문자열에서 매치되는 부분을 찾는다. 만약 매치되는 부분을 찾지 못했다면 null을 반환. 매치되는 부분을 찾았다면 매칭 결과를 저장한 배열을 반환. 이는 g 플래그가 없는 비-전역 검색에 대해 match() 메서드가 배열을 반환하는 것과 같다. 배열의 0번째 요소에는 정규 표현식과 매치된 문자열이 저장되고, 나머지 배열 요소에는 괄호로 둘러싸인 부분 표현식에 매치되는 문자열이 저장되어 있다. 만약 g 플래그가 있는 정규 표현식 상에서 exec()가 호출되면, 정규 표현식 객체의 lastIndex 프로퍼티가 현재 매치된 부분 문자열의 바로 다음 문자 위치로 생성된다. 이러한 특성때문에 한 문자열에서 모든 정규 표현식 매칭을 찾으려면 exec()를 여러 번 호출해야 한다.

var pattern=/Java/g;
var text="JavaScript is more fun than Java!";
var result;
while((result=pattern.exec(text)) !=null) {
  alert("Matched '"+result[0]+"'"+
    " at position "+result.index+
    "; next search begins at "+pattern.lastIndex);
}

 

RegExp의 다른 메서드는 test()이다. 문자열을 인자로 받고 만약 문자열에 정규 표현식과 매치되는 부분이 있다면 true를 반환한다.

var pattern=/java/i;

pattern.test("JavaScript");  //true

test()를 호출하는 것은 exec()를 호출하고 exec()의 반환 값이 null이 아닐 때 true를 반환하는 것과 같은 의미다. 따라서 lastIndex도 똑같이 적용

 

 

 

 

 

 

 

 

728x90
LIST

' > 자바스크립트 완벽 가이드' 카테고리의 다른 글

12장 서버 측 자바스크립트  (0) 2020.11.15
11장 자바스크립트 서브셋과 확장  (0) 2020.11.15
9장 클래스와 모듈  (0) 2020.11.12
8장 함수  (0) 2020.11.09
7장 배열  (0) 2020.11.08
댓글
공지사항