사이드바 영역으로 건너뛰기

게시물에서 찾기2007/02

1개의 게시물을 찾았습니다.

  1. 2007/02/01
    Regular Expression
    로이쿤

Regular Expression


우리가 검색을 할때 특정 string이 아니라 특정 pattern으로 검색하고 싶을 때가 있다.
예를들어 10-2번지 만이 아니라 10-3 10-4 10-5 .. 와 같은 경우들을 모두 찾고 싶은 경우...
이런 경우에 컴퓨터에서 사용하는 것이 바로 regular expression이다.

컴퓨터는 아주아주 깊게 들여다보면 정말 단순한 녀석이기 때문에..
똑똑한 결과를 만들어내기 위해서는 많은 삽질이 필요하다.
우리가 직접 Pattern으로 검색할 수 있는 프로그램을 짜기 위해서는..
이 단순한 녀석이 똑똑해지도록 정말 많은 노력이 필요한 것이다.

하지만 이러한 삽질을 누군가가 미리 해놓았다면..
우리는 이러한 삽질을 조금의 노력을 투자하여 가져와 사용할 수가 있다.
이러한 개념을 프로그래밍에서는 Library라고 하고..
아주 유용한 Library들이 세계 곧곧에 널려있다는 점은..
프로그래머에게는 상당히 매력적이지 않을 수 없다.
(삽질이 마구마구 줄어드니까..)

C++란 언어에서는 패턴검색을 위한 라이브러리를 기본적으로 제공하지는 않는다.
따라서 패턴검색을 하기 위해서는 라이브러리를 추가로 설치해야 하는데..
C++에서는 대표적으로 boost라이브러리에서 제공하는 Regex를 많이 사용한다.Regex를 사용하기 위해서는 boost라이브러리가 설치되어야 한다.

boost를 설치하는 과정은 꽤나 복잡하다.
실제적으로 library를 VC와 연동하기 위한 작업들이 있기 때문이다.
왜 굳이 VC의 외부에서 링크하는 방식이 아닌 내부에서 가져다 쓰게 했는지는
잘 모르겠지만 아무튼 가벼운 마음으로 가져다 쓸 library는 아니다.

Regex로 내가 하고 싶었던 것은
바로 주석 지우기와 한글 추출이었다.

1. 주석 지우기

주석을 지우기 위해서는 주석에 해당하는 Regular expression을 만들고
이것을 검색하여 ""와 replace를 시키면 된다.

주석에 해당하는 Regular Expression을 만들면 다음과 같다.

    string mcomm = "(/\*([^*]|(\*+[^*/]))*\*+/)";
    string comment = "//[^nr]*";

위의 것은 multi line comment  /* ...  */에 해당하는 내용이고
아래것은 one line comment  // ... 에 해당하는 내용이다.

one line은 딱 봐도 이해하기 쉽지만 multi line은 좀 골머리를 써야한다.
자세한 설명은
http://ostermiller.org/findcomment.html
을 참고하면 좋을 것이다.

약간 형태가 다른데.. 다른 이유는 regex의 특성이 있기 때문이다.
먼저 저기의 solution에 해당하는 구현과 regex에 해당하는 구현의 가장 큰 차이점은
.이 'n'을 제외하는가 아닌가의 차이이다.
regex는 제외하지 않고 저 위의 solution은 제외하는 구현의 regular expression이다
일반적으로 .은 n과 같은 문자는 제외한다고 하는데 regex는 포함시켰다.

그다음은 wild character에 대한 escape를 하기 위해서 들어가야 하는
back slash의 갯수가 한개인가 두개인가의 차이점이다.
이것은 regex보다는 VC++의 컴파일러가 가려내는 것 때문이다.

2. 한글 추출

이 부분이 참 아스트랄 한데.. 한번 보자..

    string jamo = "[\x{3131}-\x{318E}]";
    string syllable = "[\x{AC00}-\x{D7A3}]";
    string not_syllable = "[^\x{AC00}-\x{D7A3}]";

    string paren = """;
    string not_paren_all = "[^"+paren+"]*";

    string const_str = paren + not_paren_all + syllable + not_paren_all + paren;
    string const_str2 =
            paren + not_paren_all + not_syllable + not_paren_all + paren;


일단 위의 4가지는 준비 단계에 해당하는 것이다.
자음모음은 unicode에서 0x3131 ~ 0x318E 까지 이다.
이를 string에 넣기 위해서는 꼭 가 2개 들어가야 한다는 사실!!
안그러면 에러나요~;;;

음절은 0xAC00 ~ 0xD7A3 까지 이다.
paren과 not_paren_all은 우리가 프로그램에서 보통 string을 "로 묶어서
쓰기때문에 들어가 있는 것이다.

첫번째 const_str은 "...한글..." 과 match되는 regular expression이다
하지만 그렇지 않다는 거!!! regex에서만 그런지 아님 다른 곳에서도 그런지 모르겠지만..
이것은 한글이 아닌 것들만 쫙 골라내게 된다;;

그래서 내린 특단의 조치가 바로 const_str2이다
이것은 사실 "...한글 아닌 것..."과 match되어야 하지만..
바로 이것이 "... 한글..."과 match되는 것이 아닌가..
여기 저기 찾아보았지만 만족할 만한 대답을 보지 못했다..

혹 누가 아신다면 알려주세요..ㅜ.ㅜ

3. Multi line 주석 지우기의 한계..

안타깝게도 1번의 comment는 짧은 line에서는 가능하지만..
긴 line에서는 에러를 뱉는다.. 이유는 메모리 한계를 벗어났다는 것!
아마도 설정으로 이러한 것을 더 길게 해줄 수 있겠지만..(찾아보지는 않았다;;)
애초에 별로 효율적이지 못하다는 이야기다..

사실 regular라는 것이 굉장히 일반적인 코딩이기 때문에..
특정 상황에서는 최적이 아닐 수 있다..
따라서 이것은 차라리 다음과 같은 코드로 마무리하였다..

bool ReplaceMultiLineComment(string& src)
{
    int nSize = src.size();
    bool bStart = false;
    int nStartIndex = 0, nEndIndex = 0;
    for(int i=0;i     {
        char c = src[i];
        if(!bStart)
        {
            if(c == '/')
            {
                if(src[i+1] == '*')
                {
                    nStartIndex = i;
                    bStart = true;
                }
            }
        }
        else
        {
            if(c == '*')
            {
                if(src[i+1] == '/')
                {
                    nEndIndex = i + 2;
                    src = src.substr(0, nStartIndex) + src.substr(nEndIndex);
                    return true;
                }
            }
        }
    }
    return false;
}

별로 효율적인 코드는 아님.;;



진보블로그 공감 버튼트위터로 리트윗하기페이스북에 공유하기딜리셔스에 북마크