티스토리 뷰
발생일: 2013.04.29
문제:
지난 주 스터디 주제는 정규식이었다.
문제:
지난 주 스터디 주제는 정규식이었다.
이미 정규식은 모두 익숙하고,
챕터의 내용 자체가 짧기도 해서 금방 끝내고 커피 마시러 갔더랬다.ㅎㅎ
스터디 때 몇 가지 알려드리려고 메모해둔 게 있어 옮겨둔다.
나름대로 특징적인 내용을 뽑아 정리했던 건데, 다시 읽어보니 딱히 그렇지도 않더라.
그냥 복습 삼아 한 번 주-욱 읽어보면 좋다. ^^
해결책:
ES5에서 리터럴 정의는 항상 새로운 객체를 리턴한다.
var pat = /abc/;
ES5에서는 이 구문이 실행될 때마다 새 RegExp 객체를 생성한다.
lastIndex 속성이 잘못 사용될 것을 우려한 의도적인 설계이다.
/a/ === /a/; //--> false
구형 IE에서는 항상 같은 객체를 리턴한다.
유니코드 문자열 사용하기
유니코드로 정규식 구문을 작성할 수 있다.
예를 들어, 한글을 나타내는 아래 구문은,
/[가-힣]/
유니코드 문자열을 사용해 아래처럼 표현할 수 있다.
/[\uac00-\ud7a3]/
참고로, 특정 캐릭터의 유니코드 코드는 아래처럼 가져올 수 있다.
'가'.charCodeAt().toString(16); //--> 'ac00'
'힣'.charCodeAt().toString(16); //--> 'd7a3'
주의할 이스케이프 문자열
. : 모든 문자가 아니라, 줄바꿈이나 유니코드 라인 종료 문자를 제외한 모든 문자이다.
/./.test('\n'); //--> false
/[^.]/.test('\n'); //--> true
\w : ASCII 워드 문자
\W : ASCII 워드 문자가 아닌 것 [^a-zA-Z0-9_] 과 동일
\s : 모든 유니코드 공백
\S : 유니코드 공백 문자가 아닌 모든 문자. \w와 \S가 동일하지 않은 것에 주의한다.
[\b] : 백스페이스 문자 자체. (특수한 경우이다) 단어 경계가 아닌 것에 주의한다.
탐욕적인 반복자와 게으른 반복자 (Greedy and Lazy)
기본적으로 탐욕적(greedy)이다.
비탐욕적(게으른, lazy)하게 하려면, ?를 붙여주면 된다.
이렇게 하면 첫 번째 매칭되는 것을 리턴한다.
하지만, 의도한 대로 동작하지 않는 경우도 있다.
/a+?b/.exec('aaab'); //--> 'aaab'
'ab'를 기대하지만 그렇지 않다.
정규표현식은 문자열을 앞부분부터 탐색하다가 매치가 되면, 매칭이 완료되기 때문이다.
대체
대체는 왼쪽부터 오른쪽으로 진행된다.
왼쪽의 대체 표현식이 매치되면 매치를 종료한다.
/(a|ab)/.exec('abc'); //--> 'a'
참조
정규표현식 내에서의 그룹은 이스케이프 문자(\) 뒤에 숫자로 참조할 수 있다.
그룹 순서는 왼쪽 괄호가 열린 순서이다.
/(a)\1c/.exec('aac'); //--> aac
주의: 정규 표현식 내의 부분 표현식은, 패턴이 아니라 특정한 '문자열'에 대한 참조이다.
/(\w{2})\1/.exec('abab'); //--> 'abab'
/(\w{2})\1/exec('abcd'); //--> null
/['"][^'"]*\1/; // 따옴표 매칭의 예
그룹 매치 결과가 없는 경우 주의하기
브라우저에 따라 exec()로 그룹의 매치 결과가 없을 때 리턴하는 값이 다르다.
브라우저에 따라 null 또는 공백(''), undefined를 리턴한다.
같은 내용으로 예전에 작성했던 포스트가 있다.
그룹만 하기
(?:…) : 그룹만하고 매치 결과를 기억하지 않는다.
단어 경계
\b와 \B : ASCII 단어의 경계를 나타낸다.
이런 걸 정규표현식 앵커라고도 한다.
여기엔 ^ 와 $ 도 있다.
주의. 단어 경계는 ASCII 문자에만 적용할 수 있다.
따라서, 한글인 경우 단어 경계를 적용할 수 없다.
단어 경계 메타 문자에 대한 자세한 내용은 이전 포스트를 참고한다.
전방 탐색
(?=…)
임의의 정규 표현식을 '앵커 조건'으로 사용한다.
다음에 나오는 문자들이 괄호 안의 정규표현식과 일치해야 한다.
매치 결과에 포함하지 않는다.
(?=…) 은 긍정형 전방 탐색이고, (?!=…) 는 부정형 전방 탐색이다.
/foo(?=bar)/.exec('foobar'); //--> foo
참고로, 자바스크립트에서는 아래와 같은 형태의 후방 탐색을 지원하지 않는다.
/(?<foo)bar(?=baz)/
m 플래그
여러 줄에 걸쳐 패턴 매칭을 수행한다.
검색될 문자열이 줄바꿈 문자를 포함하고 있다면, ^와 $ 앵커가 각 줄의 시작과 끝을 나타낸다.
/^foo$/.exec('foo\nfoo'); //--> null
/^foo$/m.exec('foo\nfoo'); //--> 'foo'
String 객체의 패턴 매칭
String#search(regex);
가장 처음 매칭되는 부분의 문자열의 위치를 반환한다.
String#replace(regex, replacement);
g 플래그가 있으면 모두 바꾼다.
교체할 문자열에서 $와 숫자로 매치 결과를 참조할 수 있다.
"foobar".replace(/(bar)/, "$1baz"); //--> foobarbaz
$& : 전체 매치 결과
$1, $2, … : 그룹 결과
String#match(regex)
매치 결과를 배열로 리턴한다. 없는 경우 null.
그룹이 있다면, 그룹 매칭 결과를 순서대로 리턴한다.
g 플래그가 설정된 경우, 모든 결과를 리턴하지만, 그룹 결과는 나타나지 않는다.
"abcabc".match(/ab(c)/); //---> ["abc", "c"]
"abcabc".match(/ab(c)/g); //---> ["abc", "abc"]
String#split(regex)
RegExp 객체
정규식 문자열을 동적으로 만드는 데에 주로 쓰인다.
프로퍼티 확인은, 콘솔에서 dir(/foo/); 로 해보면 확인할 수 있다.
RegExp#exec(str)
RegExp#test(str)
exec()와 test() 는 호출될 때마다 lastIndex 프로퍼티를 갱신한다.
하지만, String 의 메서드들은 lastIndex 를 0으로 설정할 뿐이다.
ES5에서 매번 새 정규식 객체를 리턴하도록 수정한 이유는,
의도치 않게 '남아있는' lastIndex 값을 사용하는 위험을 줄이기 위해서다.
RegExp의 전역 객체
$& 는 마지막 전체 매치 결과를,
$1, $2, … 는 각각의 그룹 결과를 나타낸다.
콘솔에서 dir(RegExp)로 검색해보면 된다.
defineProperty로 getter/setter를 정의해둔 것을 볼 수 있다.
반응형
댓글
공지사항