ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ 번역 ] 손과 눈으로 기억하는 정규표현식 1
    Technique/ETC 2016. 2. 23. 17:25
    반응형

    이 기사는 다음의 사이트의 기사를 번역하여 게시한 것 입니다.

    http://qiita.com/jnchito/items/893c887fbf19e17d3ff9#%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BFatom%E4%B8%8A%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B


    아래 기사에서 사용한 정규표현식 체크 사이트

    1. Rubular

    http://www.rubular.com/

    2. 정규표현식 의 움직임을 보여주는 사이트

    http://regexper.com/


    들어가면서
    여러분 정규표현은 잘 사용하고 계십니까?
    정규표현을 사용할 수 있는건 매우 편리합니다.
    그렇지만 '정규표현 뭐야 잘 모르겠어' 사람들도 많이 계실겁니다.
    괜찮습니다. 그런 당신을 위하여 이 기사를 작성하였습니다.
    정규표현식에 대해 전혀 모르는 상태에서도 알아 들을 수 있도록 쉽게 설명하고 있기 때문에, 먼저 이 기사를 끝까지 읽어보세요
    지금은 \d{2,5}[-(]\d{1,4}[-)]\d{4} 이런 정규표현식이 무슨 마법주문 처럼 보일지 몰라도 끝까지 읽고 난뒤엔 반드시 의미를 알게될 것입니다.

    대상 독자
    이 기사는 정규표현의 예비지식이 전혀 없는 정규표현 초심자를 대상으로 하고 있습니다.
    - 정규표현은 편리하다고 자주 듣곤 있지만, 의미불명의 주문으로 만 보이니까 왠지 무서워
    - 정규표현을 공부하고자 몇번이나 노력했지만 결국 잘 안돼서 중간에 그만뒀어..

    이런 분들에게 조금더 쉽고, 간단하게 가르쳐 드리겠습니다.

    또, 기사의 본문에는 정규표현의 움직임을 시각적으로 확인가능한 편리한 사이트를 사용하고 있습니다.
    이 사이트를 사용한다면 정규펴현의 움직임을 한눈에 확인 할 수 있기에 실제로 자신의 손으로 사용해 보는 것을 적극 추천합니다.

    이 기사로 배우는 것
    이 기사 에서는 정규표현을 이용한 전화번호의 검색을 통하여, 정규표현에 관한 이하와 같은 지식을 습득합니다.
    - \d,{n,m},{n},[AB],[a-z] 의 의미
    - 정규표현의 정확성과 복잡함의 관계


    또한 예제를 실제 자신의 손으로 움직여 보면서 정규표현의 개요를 이해하고, 정규표현에 대한 거부의식을 극복하는 것을 목표로 하고 있습니다.
    그리고 눈과 손으로 기억하는 정규표현입문 은 몇회에 걸쳐 정규표현을 설명할 예정입니다.
    이 1회차의 기사에서는 지극히 초보적인 것 밖에 설명하지 않기 때문에 '이것만 읽을 수 있으면 오늘부터 정규펴현을 사용할수 있어' 라는 생각은 접어 두시기 바랍니다.

    작업 환경
    - Ruby
    - javascript
    - Atom

    이라곤 하지만 정규표현은 그 자체가 독립된 미니언어 같은 것 이기 때문에 프로그래밍 언어나 텍스트에디터와 관계없이 사용 가능 합니다.
    그렇지만 미묘하게 사용하는 기능이나, 동작이 다르거나, 실행환경에 맞춘 이스케이프문을 넣을 필요가 있거나 하기 때문에 그점은 주의하시기 바랍니다.

    이 기사의 방침
    이 기사는 어디까지나 입문기사 이기에 100% 정확힌 복잡한 정규표현 보다, 그럭 저럭 정학하고, 알기쉬운 정규표현을 중시합니다.
    이번에는 전화번호를 검색하는 정규표현을 예제로서 사용하고 있지만, 정규표현의 숙련자가 보기엔 '뭐야 그 정규표현식은 불안정해!', '나라면 이렇게 쓸거야!' 와 같은 생각을 가지고 계씬 분들이 있을 수 있습니다.
    그렇지만 본 기사에서는 어디까지나 정규표현의 기본을 이해하는 것이 제 1의 목적이고 전화번호의 완벅한 정규표현식 을 가르치는게 목적이 아니기 때문에 그점을 이해해 주십시오
    그럼 시작 하겠습니다.


    정규표현식이란
    - Wekipedia에 정규표현을 조사해보면 다음과 같이 적혀 있습니다.


    음 이것만으로는 뭔지 잘 모르겠네요
    위키의 설명을 무시하고 어디까지나 개인적인 시점에서 정규표현을 설명하라고 한다면 '패턴을 지정하고 문자열을 효율적으로 검색, 치환하기위한 미니 언어'
    라고 생각합니다.
    뭐 어찌됫든 초심자분들은 잘 모르시겟죠
    괜찮습니다.
    지금의 단계에서는 그만큼 깊이 생각하지말고 이 기사를 읽어 나가신다면 최후에는 정규표현이 무엇인가, 무엇이 어떻게 편리한지 알게 될 것입니다.
    그리고 위키에 나와 있는 대로 정규표현은 영어로 Regular expression 이라고 말합니다.
    프로그래밍언에나 에디터상에서 간략히 Regex Regexp 라고 표현하는 것이 많기 때문에 이 약칭도 머리에 넣어 둡시다.

    전화번호를 검색
    우선 처음엔 정규표현식으로 전화번호를 검색해봅시다.
    가장먼저 이런 텍스트를 준비해 봅시다.

    名前:伊藤淳一
    電話:03-1234-5678
    住所:兵庫県西脇市板波町1-2-3

    본 기사에서는 정규 표현을 알기쉽게 학습하기 위하여 이번에는 Rublar라고 하는 웹사이트를 이용합니다.
    사이트로 이동하여 위 텍스트를 아래처럼 복사합니다.
    그뒤 정규표현식 란에 \d 를 입력해주세요



    그렇게 한다면 매치 결과란에 하늘색으로 문자가 표시 됩니다.
    하늘색으로 표시된것이 정규표현에 매치된 부분, 즉 검색하여 찾은 부분이 됩니다.
    이곳에서는 숫자가 전부 하늘색으로 되어 있습니다.

    방금전 입력한 \d 는 정규표현에서는 득별한 의미를 가지고 있습니다.
    이런 특별한 문자를 메타문자 라고 부릅니다.
    \d 는 [1개의 숫자]를 의미하는 메타문자 입니다. ( 문자의 집합을 나타내기에 문자 클래스 라고 불려집니다 )
    보통의 검색이라고 한다면 \d 는 "\d" 같은 문자열 그 자체를 검색합니다만, 정규표현식에서의 \d 는 1개의 숫자를 검색합니다.
    이후 정규표현안에 \d 가 튀어 나온다면 '아 이건 숫자를 의미하는구나 '라고 기억해 두세요

    메타문자를 연결하여 문자열을 검색 해보자
    그럼 이상태 그대로라면 전화번호만을 검색할 수 없습니다.
    거기서 다음과 같은 정규표현을 입력주세요
    \d\d-\d\d\d\d-\d\d\d\d


    이렇게 하면 전화번호만 검색할 수 있습니다.
    \d는 1개의 숫자 이기에 \d\d는 2개의 숫자를 의미힙니다.
    '-' 은 메타문자가 아니기에 '-' 의 문자 그 자체를 나타냅니다. ( 그렇지만 사용법에 따라서는 - 도 특별한 의미를 가집니다. 본기사의 후반에 설명합니다 )


    따라서 \d\d-\d\d\d\d-\d\d\d\d 는 숫자2개 하이픈 숫자4개 하이픈 숫자4개가 나열된 문자열을 검색하고있다 라는 의미가 됩니다.
    테스트로 전화번호를 바꿔봅시다.
    숫자2개 하이픈 숫자4개 하이픈 숫자4개 라는 패턴은 변하지 않기에 이것도 검색될 것입니다.


    javascript에서도 정규표현을 사용할 수 있기 때문에 js를 평소 자주 사용하신다면 js상에서 동작 시켜보는 것도 좋습니다.


    Rubular는 루비에서 동작하는 정규표현을 시뮬레이션 하는 사이트입니다만,  js에도 Scriptular라고 하는 거의 같은 사이트가 존재합니다.


    js상에서의  정규표현의 동작을 확인하고 싶은경우 이쪽을 이용하면 좋다고 생각합니다.
    물론 코드내의 정규표현을 사용하는 것도 가능합니다.

    1
    2
    3
    var text = "名前:伊藤淳一\n電話:03-1234-5678\n住所:兵庫県西脇市板波町1-2-3";
    text.match(/\d\d-\d\d\d\d-\d\d\d\d/g);
    // => ["03-1234-5678"]
    cs


    또한 /\d\d-\d\d\d\d-\d\d\d\d/g 의 젤 끝의 g는 글로벌 옵션이라고 불리는 것으로 이하와 같은 차이점이 존재합니다.
    - g 없음 : 최초의 1개 가 검색된다면 검색 종료
    - g 존재 : 일치하는 문자열을 전부 검색

    여러가지 시외국번에 대응

    전화번호는 항상 숫자2개 하이픈 숫자4개 하이픈 숫자4개 로 는 사용되지 않습니다.
    휴대전화번호인 "090-1234-5678" 처럼되고  "0795-12-3456"같이 시외국번이 4자리가 되는 경우도 있습니다.
    또는 지방에 따라서는 "04992-1-2345" 같이 5자리가 되는 경우도 있습니다.
    Rubular 에
    名前:伊藤淳一
    電話:03-1234-5678
    電話:090-1234-5678
    電話:0795-12-3456
    電話:04992-1-2345
    住所:兵庫県西脇市板波町1-2-3
    를 입력해봅시다.


    보는 것과 같이 방금전 사용한 정규표현식으론 새롭게 추가된 전화번호를 검색 할 수 없습니다.
    이 4개의 전화번호에는 어떤 법칙이 있을까요?
    정규표현을 사용할 때는 우선 검색대상문자열의 패턴을 발견하는것이 중요합니다.
    이번 같은 경우엔 다음과 같은 법칙이 있다고 말할 수 있겠죠
    숫자2~5개 하이픈 숫자 1~4개 하이픈 숫자4개
    그뒤엔 이들을 정규표현으로서 표현하는 것이 된다면 OK입니다.
    문자의 개수를 한정할때에는 {n,m} 나 {n} 와 같은 메타문자를 사용합니다. ( 문자량을 지정하는 것은 '양지정자' 라고 합니다 )
    {n,m} 은 바로전의 문자가 n 개 이상、m개 이하를 의미합니다.
    또한  {n} 로 사용하면 n개의 문자 의 의미가 됩니다.

    따라서 정규표현식은 다음과 같이 됩니다.
    \d{2,5}-\d{1,4}-\d{4}



    Rubular에 이 정규표현을 입력하면 올바르게 전화번호를 검색하는 것이 가능합니다.
    정규표현에서 {와 } 도 특별한 의미를 가지고 있다는 것을 기억해 두세요

    하이픈뿐만아니라 괄호에도 대응한다

    전화번호는 다음과같이 표기될 경우도 있습니다.
    하이픈이 아니라 괄호를 사용하는 케이스 입니다.

    "03(1234)5678"
    하이픈이 와도 괄호가 와도 어느쪽 이라도 전화번호가 검색 가능한 정규표현은 있을까요?
    괜찮습니다. 그럴 경우에도 젖ㅇ규표현식으로 검색가능 합니다.
    우선 Rubular 에 다음과 같은 텍스트를 넣어 주세요

    名前:伊藤淳一
    電話:03(1234)5678
    電話:090-1234-5678
    電話:0795(12)3456
    電話:04992-1-2345
    住所:兵庫県西脇市板波町1-2-3



    당연히 괄호를 사용한 전화번호는 검색에 실패했습니다.
    이번에도 역시 법칙을 찾는 것 부터 시작합니다.
    이번의 경우에는 다음과 같은 법칙이 있다는 것을 알 수 있겟죠
    숫자2~5자 하이픈 또는 괄호, 숫자 1~4자 하이픈 또는 괄호, 숫자 4자
    새롭게 등장한것은 하이픈 또는 괄호( 열기 ) 와 하이픈또는 괄호(닫기)와 같은 A 또는 B의 패턴 입니다.
    A 또는 B중 어느것 1문자 를 나타내는 경우엔 [AB]라고 작성합니다. ( 문자의 경우를 나타내기에 , 이것또 문자클래서의 한종류입니다 )
    [] 안의 문자수에 제한은 없습니다.
    [ABC]라고 작성하면 A또는 B또는 C 셋중 이느것 한 문자 의 의미가 됩니다.
    하이픈 또는 괄호 ( 열기 ) 와 하이픈 또는 괄호 ( 닫기 ) 는 각각 [-(], [-)]라고 표시됩니다.
    기호만이 열거되어 있어 알기 어려울 것 같습니디만 [AB]의 형식이 되어 있다는 것을 확인해 주세요
    이것들을 다 염려해서 정규표현을 다시 쓴다면 다음과 같이 됩니다.
    \d{2,5}[-(]\d{1,4}[-)]\d{4}
    이것을 Rubular에 넣으면 다윽뫄 같이 전화번호가 검색 됩니다.


    정규표현의 지식이 없으면 \d{2,5}[-(]\d{1,4}[-)]\d{4} 은 수수께끼 같은 암호로밖에 보일테지만,
    여기까지 이 기사를 읽어온 사람이라면 메타문자의 의미와 메타문자가 아닌 보통의 문자의 구별이 가능할 것입니다.
    덧붙여 이번에 나온 둥근 괄호 ( 와 ) 는 []의 밖에 사용하면 특별한 의미를 가지게 됩니다.
    그것에 대해서는 다음회 이후의 기사에서 설명 드리겠습니다.

    하려고 한다면 전화번호를 사용해서 아직 더 많은 정규표현식을 나타내는 것도 가능합니다만 점점 기사가 길어지기 때문에 전화번호를 사용한 정규표현식은 일단 여기서 종료합니다.

    []안의 하이픈은 주의가 필요

    방금전 정규표현에서는 [-(]나 [-)]로 작성하여 하이픈 또는 괄호 열기,와 하이픈 또는 괄호 닫기,를 표현 하였습니다.
    일반적으로 [AB]와  [BA]로 써도 같은 움직임이 됩니다.
    그러나 - 뿐만으로는 특별한 의미를 가지기 때문에 주의가 필요합니다.
    실은 [a-z]로 쓰면  [a 또는 b 또는 c 또는 ... y또는 z ]의 의미가 됩니다.
    [ a또는  하이픈 또는 z ] 가 아니니 주의 하세요
    동시에 [a-zA-Z0-9] 로 사용하면 [a또는 b또는 ... A또는 B 또는 ... 0또는 1또는 ... 9 ]의  의미가 됩니다.( 간단히 말하면 이것은 영문,숫자 1문자 를 의미합니다 )
    다시말해 [a-z]와 같은 하이픈은 문자의 범위를 의미합니다.
    그러나 [-az]나 [az-]와 같은 하이픈이 []의 최초, 또는 최후에 위치한다면 하이픈 1문자의 의미로 변합니다.
    그렇기 때문에 [-az] 나 [az-]는 [a또는 z 또는 하이픈 셋중1문자 ] 의 의미가 됩니다.
    실제로 적어 봅시다.
    Rubular 에 다음과 같이 입력합니다.


    [0-9]라는 정규표현식을  입력하면 숫자만 매치됩니다. 즉 \d와 같은 의미 입니다.
    반면 [-09]로 입력하면 0또는 9또는 하이픈 이 매치됩니다.

    이렇듯 [] 의 안에는 사용하는 방법에 따라 하이픈의 의미가 바뀌는 것을 기억해 두세요



    검색의 정확성과 정규표현의 복잡성에 대하여
    이번에는 전화번호를 검색하는데 \d{2,5}[-(]\d{1,4}[-)]\d{4} 라는 정규표현식을 사용하였습니다.
    그러나 이것은 어디까지나 숫자 2~5개 하이픈또는 괄호 열기, 숫자 1~4개 하이픈 또는 괄호닫기, 숫자 4개 라는 문자열을  매치할 뿐입니다.
    전화번호만을 완벽하게 검색하는 정규표현식은 결코 없습니다.
    검색 대상의 문자열에 따라 전화번호이외의 문자열에 매치 하는 경우도 있습니다.
    예를 들어  "9999-99-9999"는 실존 하지 않는 전화번호이고, "03(1234-5678" 같이 괄호와 하이픈이 혼재하는 희안한 문자열에 매치해버리고 맙니다.
    이런 예외적인 케이스를 전부 배제하려고 한다면 우선 전화번호의 사양을 완벽히 이해하고, 그 사양을 완전히 반영한 정규표현식을 작성해야만 합니다.
    그리고 아마도 그 정규표현은 대단히 복잡해질 것입니다.

    전화번호를 완벽히 표현하는 정규표현의 만드는 방법은 잘 모르겠지만 전화번호 대신에 전자메일 주소의 정규표현을 알아봅시다.
    인터넷을 조사해보면 RFC에 쥰하는 전자메일 주소의 99.9%정확한 정규표현이 공개되어 있었습니다.


    http://emailregex.com/


    링크를 보신다면 알 수 있듯이 엄청 복잡한 정규표현이 됩니다.
    매회 이런 복잡한 정규표현을 생각할 시간은 없을 거고, 혹시 잘 움직이지 않을 경우 정규표현을 읽고, 해석하고 디버깅하는 것도 거의 불가능 합니다.
    이렇기에 현실적으로 100% 완벽엔 아니고 거의 거의 정확한 레벨의 정규표현으로 타협하는 경우가 있습니다.
    그리고 거의 정확한 의 말은 요건에 따라 달라집니다.
    예를 들어 대량의 텍스트 로부터  전화번호의 같은 문자열을 검출해서 인간의 시점에서 판단한다면 이번에 만든 \d{2,5}[-(]\d{1,4}[-)]\d{4} 로 충분합니다.
    그러나 웹 폼의 입력 체크에 정규표현을 사용하는 것이라면 좀더 정확도를 높여야 할 것입니다.
    예를 들어 1번째문자는 0, 2번째문자 부터는 0이외의 숫자 라고 말할수 있는 것으로 0[1-9]\d{0,3}[-(]\d{1,4}[-)]\d{4}

    으로 한다면 약간 정확도가 올라갑니다.


    보는 것과 같이 "9999-99-9999"는 매치 하지 못합니다. 그러나 "03(1234-5678"에는 아직 매치하고 있습니다.
    Ruby나 Javascript와 같은 프로그래밍 언어에서 정규표현을 사용하는 것이라면 정규표현을 사용하여 어느정도 문자열을 검출하고 남은 작업은 프로그래밍언에의 기능을 사용하여 정확도를 높이자
    와 같은 하이브리드적인 접근도 사용하는 것도 가능합니다.

    결론
    본기사에서는 정규표현에 대하여 이하와 같은 것을 배울 수 있엇습니다.
    - \d 는 숫자1개를 나타냄
    - {n,m} 직적문자 1개 이상 、m개 이하를 나타낸다
    - {n} 은 직전문자가 딱 n개 인 것을 나타냄
    - [AB] 는 A또는 B 중 1문자 인 것을 나타냄
    - [a-z]와 [-az] 에서의 하이픈의 의미는 다르다
    - 정규표현의 정확성과 북잡성은 trade off 하는 것이 많다.

    이번에는 전화번호를 검색한다 라는 테마였기에 아직까진 바리에이션이 모자랍니다.
    실무에서 원하는 대로 문자열을 검색하기 위해서는 조금더 많은 정규표현의 룰을 기억해야만 합니다.

    그러나 초심자인 분은 이번의 기사에서는 정규표현을 잘 다루기 보다는 오히려 다음과 같은 것을 느끼신다면 OK 라고 생각합니다.
    - 지금까지는 텍스트에디터로 보통의 문자열 검색밖에 사용하지 못햇지만, 정규표현을 사용한다면 지금까지 눈으로만 검색하던 문자열도 검색할수 있다는 자신감
    - 지금까지 문자열처리하는 프로그램에서는 1문자씩 루프돌리거나 특정문자로 split하거나 이것저것 귀찮은 처리를 많이 했지만 정규표현을 사용한다면 그런 귀찮은 처리 없이 깔끔하게 처리할수 있을 자신감
    - 지금까지 정규표현을 보고도 의미불명의 주문으로 밖에 보이지 않았지만 이 기사를 읽고나서 정규표현을 보는눈이 조금은 바뀌었다는 부분

    이런식으로 느낌을 받으신다면 다음회 이후의 기사에서 점점더 새로운 지식을 흡수 할 수 있을 것입니다.

    덧붙여 다음회이후는 다음과 같은 메타문자나 처리를 설명할 예정입니다.
    - 자주사용할만 할 각종 메타문자
    - 메타문자의 이스케이프
    - 캡쳐를 사용한 문자열 치환

    반응형

    댓글

Designed by Tistory.