정규 표현식 연습

문법

문자열을 따옴표로 감싸는 방식으로 정규 표현식 패턴은 슬래시(/) 사이에 적는다.
문자열의 search 메소드는 인자로 던달된 문자열이 발견된 위치를 반환하는 indexOf 처럼 동작하지만 문자열 대신 정규 표현식을 인자로 취한다.

	
							// 문자열 search메서드
							var result = "doubledare".search(/le/);
						

문자 집합 매칭

[와 ] 문자는 정규 표현식 내에서 특별한 의미를 지닌다. 문자로 구성된 목록을 이 두 문자로 감싸면 이 문자 중 하나가 발견될 때 매칭된다.

점(.)은 '줄 바꿈 문자가 아닌 모든 문자'를 가리킬 때 사용할 수 있다.
\d 는 '모든 숫자', \w 는 '단어' 문자와 매칭, \s 는 공백문자(탭, 개행, 공백)와 매칭
\d, \w, \s 문자는 대문자로 치환해서 의미를 부정할 수 있다. \S는 공백이 아닌 문자와 매칭.

단어와 문자열 경계 매칭

문자열이 시작하는 부분에서 패턴이 시작하거나 문자열의 끝에서 끝난다는 것을 확실히 해야 할 때가 있다. 특별한 ^와 $ 문자를 이용하면 이렇게 할 수 있다. ^ 문자는 문자열의 시작과 매칭되고, $ 문자는 문자열의 끝과 매칭된다.

첫 번째 정규 표현식은 a 문자가 포함된 문자열과 매칭되는 반면, 두 번째 정규 표현식은 "a" 문자열하고만 매칭된다. 참고로 정규 표현식은 객체이며, 메소드도 있다. test 메서드는 특정 문자열이 표현식과 일치하는지 여부를 가리키는 불리언 값을 반환한다.

\b 이스케이프 문자는 '단어 경계'와 매칭되며, 여기서 단어 경계는 문장 부호, 공백, 또는 문자열의 시작이나 끝이 될 수 있다.

반복 패턴

정규 표현식 안에서는 하위 패턴의 반복을 표현하는 것이 가능하다. 요소의 끝에 애스터리스크(*)를 집어넣으면 0번을 포함해서 몇 번이고 반복할 수 있다. 더하기(+)는 같은 역할을 하지만 적어도 한 번은 패턴이 나타나야 한다는 것을 의미한다. 물음표(?)는 요소가 선택적임을 의미하며, 요소가 한 번도 나타나지 않거나 한 번만 나타날 수 있다.

필요하다면 중괄호를 이용해 요소가 나타날 수 있는 횟수를 지정할 수 있다. 중괄호 안에 숫자를 지정하면(예,{4}) 요소가 나타나야 하는 정확한 횟수를 지정할 수 있다. 두 숫자 사이에 콤마를 집어넣으면({3, 10}) 패턴이 최소한 첫 번째 숫자만큼 나타나야 하고 최대한 두 번재 숫자만큼 나타나야 한다는 것을 가리킨다. 이와 비슷하게 {2, }는 두 번 이상 나타나야 한다는 것을 의미한고, {,4}는 4번 이하를 의미한다.

다음은 날짜를 매칭하기 위한 좀 더 유연한 패턴이다.

/\d{1,2}/ 와 /\d\d?/ 표현식은 '하나 또는 두 개의 숫자'를 표현하는 두 가지 방법이다.

하위 표현식 그룹화

종종 한 번에 하나 이상의 문자에 대해 *나 +와 같은 특수 문자를 사용해야 할 때가 있다. 이때 괄호를 이용해 정규 표현식의 일부를 하나로 묶어 전체 그룹을 대상으로 특정 작업을 하는 것도 가능하다. 다음 예제를 살펴보자.

hoo+ 패턴은 h 뒤에 o 문자가 2개 이상 나타나는 경우에 매칭된다. (hoo+)+를 지정하면 이 패턴을 전체에 걸쳐 한 번이상 반복시킬 수 있다.

여기서 정규 표현식 끝의 i를 눈여겨보자. 닫는 슬래시 뒤에는 정규 표현식에 '옵션'을 추가할 수 있다. 여기서 i는 정규 표현식이 대소문자를 구분하지 않는다는 것을 의미하며, 패턴에 소문자 b가 있어도 문자열 내의 대문자 B와 매칭된다. 이후 '전역'을 나타내는 g 옵션에 대해서도 살펴본다.

후보 선택

좀 더 고급 패턴에 속하는 '분기' 패턴의 경우 파이프 문자(|)를 이용해 패턴상에서 여러 요소 가운데 하나를 선택하게 할 수 있다. 다음 예제를 살펴보자.

이렇게 하면 문자열에 scared나 holy가 포함돼 있고, 이어서 cow, bovine, bull, taurus 단어 가운데 하나가 나오는 문자열과 매칭된다. 참고로 여기서는 괄호를 사용해야 하는데, 그렇게 하지 않으면 scared, holy, cow, bovine 등과 같은 것 중에서 선택될 것이기 때문이다.



매치과 치환

match 메소드

문자열에는 match라는 메소드가 있는데, 이 메소드는 정규 표현식을 인자로 전달받는다. 이 메소드는 매칭이 실패하면 null을 반환하며, 매칭이 성공하면 매칭된 문자열로 구성된 배열을 반환한다. 다음 예제에서 이를 확인할 수 있다.

반환된 배열의 첫 번째 요소는 항상 패턴 전체와 매칭된 문자열의 일부이다. 세번째 예제에서 확인할 수 있듯이 패턴에 괄호로 감싸진 부분이 있으면 매칭된 부분도 배열에 추가된다. 종종 이렇게 되면 문자열의 일부를 추출하는 작업이 아주 수월해진다.

이 버전의 함수는 더 이상 이전 함수가 아니며, 실제로 입력 내용이 예상한 것과 같은지 검사하고 올바르지 않은 입력일 경우 예외를 던진다. 이 작업은 정규 표현식을 쓰지 않고는 힘든 일이었는데, 숫자에 하나 또는 2 개의 자릿수가 포함돼 있고 슬래시가 예상한 지점에 있는지 확인하기 위해 여러 번에 걸쳐 indexOf를 호출했기 때문이다.

정규 표현식과 replace 메소드

문자열 값의 replace 메소드에는 첫 번째 인자로 정규 표현식을 전달할 수 있다.

여기서 정규 표현식 끝의 g 문자를 눈여겨보자. g는 "전역(global)"을 나타내며, 패턴 과 매칭되는 문자열의 모든 부분을 치환해야 한다는 의미다. 이런 g를 생략하면 첫 번째 o만이 치환될 것이며, 이것은 흔히 저지르는 실수다.

때때로 치환하는 문자열의 각 부분을 유지해야 할 때가 있다. 예를 들어 사람들의 이름이 포함된 아주 긴 문자열이 있다고 해보자. 이 문자열의 각 줄에는 이름이 하나씩 나오며, 간단히 "이름", "성" 형시으로 돼 있다. 성과 이름의 위치를 콤마를 제거해 '성 이름' 형식으로 바꾸고 싶다면 다음과 같은 코드를 이용하면 된다.

대체 문자열의 $1과 $2는 패턴에서 괄호로 감싼 부분을 가리킨다. $1은 괄호로 묶은 첫 번째 쌍을 대상으로 매칭된 텍스트로 치환되고, $2는 괄호로 묶은 두 번째 쌍을 대상으로 매칭된 텍스트로 매칭되며, 이런 식으로 $9까지 이어진다.

패턴에 괄호로 묶은 부분이 9개를 넘으면 이 방법도 통하지 않는다. 하지만 정규 표현식을 이용해 문자열의 일부를 치환하는 훨씬 더 유연한 방법이 있다. replace 메서드에 전달한 두 번째 인자가 문자열이 아니라 함수 값이라면 매칭된 부분이 발견될 때마다 이 함수가 호출되며, 매칭된 텍스트가 해당 함수에서 반환한 것으로 치환된다. 함수에 전달된 인자는 매칭된 요소이며, 이것은 match 메서드에서 반환하는 배열에 담긴 값과 비슷하다. 즉 첫 번째 인자는 전체 매칭이고, 그 이후로는 패턴에서 괄호로 묶은 부분에 대한 인자가 온다.

다음 예제를 살펴보자.

그리고 다음은 좀 더 깜찍한 예제다.

이 예제에서는 문자열을 전달받아 숫자가 나온 후 알파펫과 숫자로 구성된 단어가 나오는 부분을 모두 찾아 숫자에서 모두 1을 뺀 문자열을 반환한다.

(\d+) 그룹은 함수에 전달되는 amount 인자에 해당하며, (\w+) 그룹은 unit에 해당한다. 함수에서는 수량을 숫자로 변환하고(이 부분은 항상 동작하는데, 숫자는 \d+와 매칭되기 때문이다), 1이거나 0인 경우에 대비해 약간의 조정 작업을 한다.(부가 설명, replace - mozilla developer network - ()로 매칭대상을 그룹화하고 그 그룹은 이후 파라미터로 호출되는 함수의 각각의 인자가 된다. replace가 파라미터로 호출하는 함수의 첫번째 인자는 함수로 수행하게될 작업대상이 되는 문자열(match)을 가리키고 나머지는 그 문자열 내에서 매칭하게되는 패턴들이된다. 부가 설명 페이지를 보면 유동적인 패턴 인자 외에 추가적인 인자들이 있다. 확인 요망)

replace에 함수를 전달하는 이런 기법은 5장에서 작성한 HTML 이스케이프 함수를 좀 더 효율적으로 만드는 데 활용할 수 있다. 5장에서 살펴본 함수가 다음과 같다는 사실을 기억할 것이다.