C++11부터 std::regex가 추가됐는데요, 그 전까지는 boost::regex 또는 tr1::regex를 사용했습니다.

regex 객체를 생성할 때 syntax option을 줄 수 있는데 자세히 알아보겠습니다.

 

 

// NAMESPACE regex_constants
namespace regex_constants {
    // constants used in regular expressions
    enum syntax_option_type : int { // specify RE syntax rules
        ECMAScript = 0x01,
        basic      = 0x02,
        extended   = 0x04,
        awk        = 0x08,
        grep       = 0x10,
        egrep      = 0x20,
        _Gmask     = 0x3F,

        icase    = 0x0100,
        nosubs   = 0x0200,
        optimize = 0x0400,
        collate  = 0x0800
    };
};

MSVC의 regex 헤더에서 regex_constants::syntax_option_type 부분입니다.

bitmask flag이고, 정규식 문법 규칙을 고르는 flag과 정규식 검색 옵션 flag로 구분됩니다.

  • 정규식 문법 규칙: 최대 한 개까지 설정할 수 있습니다
    • ECMAScript: Flag을 넣지 않으면 기본값으로 설정됩니다
    • basic: BRE로 컴파일됩니다
    • extended: ERE로 컴파일됩니다
    • awk
    • grep
    • egrep
  • 정규식 검색 옵션
    • icase: 알파벳 대소문자를 구분하지 않습니다
    • nosubs: 캡처 그룹을 사용하지 않습니다
    • optimize: 문자열 매칭 시간이 빨라질 수 있도록 최적화합니다. regex 객체 생성에 더 많은 시간이 걸릴 수 있습니다. 예를 들면 NFA를 DFA로 바꾸는 등의 방법이 있을 수 있습니다.
    • collate: [a-b]처럼 문자열 범위를 사용할 때 로케일을 고려합니다.

 

 

// CLASS TEMPLATE basic_regex
template <class _Elem, class _RxTraits = regex_traits<_Elem>>
class basic_regex : public _Regex_base { // regular expression
	using flag_type = regex_constants::syntax_option_type;

    static constexpr flag_type icase      = regex_constants::icase;
    static constexpr flag_type nosubs     = regex_constants::nosubs;
    static constexpr flag_type optimize   = regex_constants::optimize;
    static constexpr flag_type collate    = regex_constants::collate;
    static constexpr flag_type ECMAScript = regex_constants::ECMAScript;
    static constexpr flag_type basic      = regex_constants::basic;
    static constexpr flag_type extended   = regex_constants::extended;
    static constexpr flag_type awk        = regex_constants::awk;
    static constexpr flag_type grep       = regex_constants::grep;
    static constexpr flag_type egrep      = regex_constants::egrep;
};

regex 클래스 템플릿을 보면 flag들이 똑같이 복사돼있는 걸 확인할 수 있습니다. 예를 들면 std::regex::icase, std::regex_constants::icase 둘 다 똑같은 값이겠죠.

같은 값이면 길이가 짧은 걸 쓰는게 쓰기 편할 것 같습니다

 

 

#include <iostream>
#include <string>
#include <regex>
 
int main()
{
    std::string str = "zzxayyzz";
    std::regex re1(".*(a|xayy)"); // ECMA
    std::regex re2(".*(a|xayy)", std::regex::extended); // POSIX
 
    std::cout << "Searching for .*(a|xayy) in zzxayyzz:\n";
    std::smatch m;
    std::regex_search(str, m, re1);
    std::cout << " ECMA (depth first search) match: " << m[0] << '\n';
    std::regex_search(str, m, re2);
    std::cout << " POSIX (leftmost longest)  match: " << m[0] << '\n';
}

cppreference에 있는 예제입니다. re1은 flag를 넣지 않아 ECMAScript로 설정됐고, re2는 extended flag를 줘서 ERE로 설정된 모습입니다.

POSIX는 "leftmost longest" rule이기 때문에 검색값에 차이가 발생할 수 있습니다. 특히 주의해야 할 부분은 XML, HTML같은 마크업 언어라고 합니다. 태그를 검색할 때 POSIX를 사용하면 원하는 대로 결과가 나오지 않을 수 있습니다.

반응형