티스토리 뷰

Daylogs/Javascript

정규식 메모

ohgyun 2013. 4. 29. 16:09


발생일: 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를 정의해둔 것을 볼 수 있다.




반응형
댓글
공지사항