집에 좀 가자 퇴근하고 싶은 개발자

C++에서 regex 쓸 때 주의점


C++11 이후 버전에서 공식적으로 정규표현식을 사용하게 되면서 C++에서 문자열을 파싱하기가 한결 수월해졌다. 하지만 오늘 업무 중에 regex 의 동작 방법을 잘 몰라서 고생할 뻔했기에 기록을 남겨둔다.


아래의 코드는 regex를 사용하는 기본 코드이다.


#include <iostream>
#include <regex>

using namespace std;

int main() {

  regex rPattern("(\\w+)_(\\d+)");
  smatch mResult;

  string sInput = "abc_123";
  if (regex_match(sInput, mResult, rPattern))
	  cout << mResult[1] << " " << mResult[2] << endl;

  return 0;
}


위의 코드를 실행하면 다음과 같은 결과를 얻는다.

abc 123


그런데, regex에 사용되는 input string의 scope를 조금 다르게 하면 예상치 못한 결과가 나온다.


#include <iostream>
#include <regex>

using namespace std;

int main() {

  regex rPattern("(\\w+)_(\\d+)");
  smatch mResult;

  {
    // if문이라던지.. for 안에서 input을 받아서 밖으로 넘기고 싶다....
    string sInput = "abc_123";
    if (regex_match(sInput, mResult, rPattern))
      cout << mResult[1] << " " << mResult[2] << endl;
  }

  cout << mResult[1] << " " << mResult[2] << endl;
  return 0;
}


위의 코드를 작성하면서 다음과 같은 결과를 원했다.

abc 123

abc 123


하지만 실제로 코드를 실행해보면 다음과 같이 나온다.

abc 123

  bc 123 // 꼭 이렇게 나오지는 않을 수 있다.


실제로 smatch는 match_results<string::const_iterator> 의 typedef 형인데, 해당 템플릿 타입의 멤버변수 _Org 을 갖는다. regex_match를 수행하는 과정에 레퍼런스로 넘어간 smatch 변수가 채워지게 되고, 이때 _Org이 input string을 가르키는 iterator가 된다. 따라서 input string의 scope 밖으로 넘어가면 smatch 객체 내부가 깨지게 되는 것으로 보인다.



한 이틀 고생할 만한 것이었는데 다행히 15분만에 찾고 넘겨서 다행이다.

regex를 쓸 때에는 input string의 scope 내에서 사용하도록 하자.