[C++] 정규식 표현 std::regex으로 문자열 찾기
C++11에 포함된 <regex> 라이브러리에 정규식 표현과 관련된 기능이 있다.
std::regex
정규식 문자열을 받아 정규식을 표현하는 개체
std::regex rx("[\\w]+"); // 단어 단위로 하나이상 매칭시키는 정규식
C++/C# 정규식 표현 치팅 시트
자주 사용되는 정규식 표현
- [A-Za-z] : 영소대문자 집합 == [\\w]와 같은 의미
- [\\w\\d] : 영소대문자 혹은 숫자로 이루어진 단어
- [a]+ : 문자열 a가 적어도 하나 이상, [a]? a가 하나 있거나 없거나
- [A-Z]{3,4} : 영대문자가 3~4글자 포함되어야함
- ^[\\d] : 숫자로 시작하는, [\\d]$ 숫자로 끝나는
- a.c : 와일드 카드 (abc, adc, aed), a*e : a로 시작하고 e로 끝나는 모든 문자열
- \w / \d와 같은 경우 이스케이프 문자가 문자열 내에서 캐치되도록 \\(\\w, \\d)를 사용해야한다.
- 그룹화 (정규식 표현1)(정규식 표현2)...
사용 패턴
std::regex_match
1. 전체 문자열을 대상으로 해당 정규식 표현이 매칭되는 지 알고 싶은 경우
bool match = std::regex_match("대상 문자열", rx);
#define REG_MATCH(expression, text)\
std::regex reg_match(expression);\
std::cout << "text: " << text << std::endl;\
std::cout << "regex: " << expression << " match: " << std::boolalpha << std::regex_match(text, reg_match) << std::endl;
static constexpr const char* text3 = "---this is an example----"
static void MatchExample3()
{
const char* exp = "-+([A-Za-z ]+)-+";
REG_MATCH(exp, text3); // true
}
2. 그룹을 이용한 정규식 표현으로 문자열 캐치하기
std::regex_match와 std::smatch를 이용하여 정규식의 그룹들을 분리해낸다.
std::regex_match가 true인 경우 전체 문자열이 첫번째 그룹이 되고
그 이후 (괄호) 순서에 따라 그룹 인덱싱으로 분리해낼 수 있다.
static void MatchExample6()
{
const char* exp = "^(\\w+)://([\\w.]+)(:(\\d+))?([\\w./]+)?(\\?([\\w=]*))?(#([\\w]+))?$";
std::string uri("https://www.naver.com:80/kr/index.html?lite=true#ui");
std::regex rx(exp);
auto matches = std::smatch();
if (std::regex_match(uri, matches, rx))
{
if (matches[1].matched)
{
std::cout << "protocol: " << matches[1].str() << std::endl;
}
if (matches[2].matched)
{
std::cout << "domain: " << matches[2].str() << std::endl;
}
if (matches[4].matched)
{
std::cout << "port: " << matches[4].str() << std::endl;
}
if (matches[5].matched)
{
std::cout << "path: " << matches[5].str() << std::endl;
}
if (matches[7].matched)
{
std::cout << "query: " << matches[7].str() << std::endl;
}
if (matches[9].matched)
{
std::cout << "fragment: " << matches[9].str() << std::endl;
}
}
}
std::sregex_iterator
3. 전체 문자열 중 정규식 표현에 매칭되는 부분 문자열을 모두 찾는 경우
static void MatchExample2()
{
static constexpr const char* example = "(This) {is} <an> [example]";
const char* exp = "[\\[\\{\\(\\<]([A-Za-z]+)[\\]\\}\\)\\>]";
std::regex rx(exp);
std::string sss(example);
std::cout << "text: " << example << std::endl;
std::sregex_iterator iter(sss.begin(), sss.end(), rx);
std::sregex_iterator iterEnd;
std::cout << "found: ";
while (iter != iterEnd)
{
if (iter->size() > 1)
{
std::cout << "(" << (*iter)[1] << ") ";
}
++iter;
}
std::cout << std::endl;
}
4. 정규식 표현과 일치하는 모든 부분 문자열의 수
static void MatchExample7()
{
const char* exp = "apple|Apple";
static constexpr const char* tt = "My Apple device counts apples for apple service as an Apple user like an apple.";
std::regex rx(exp);
std::string str(tt);
std::cout << "text: " << str << std::endl;
std::sregex_iterator iter(str.cbegin(), str.cend(), rx);
std::sregex_iterator iterEnd;
auto count = std::distance(iter, iterEnd);
std::cout << "expression: " << exp << std::endl;
std::cout << "count: " << count << std::endl;
}
std::regex_replace
5. 정규식 표현으로 문자열 치환하기
std::string dayMonthYearDate("31-10-2020");
const char* exp = "(\\d{1,2})(.|-)(\\d{1,2})(.|-)(\\d{4})";
std::regex rx(exp);
// "2020-10-31"
std::string yearMonthDayDate = std::regex_replace(dayMonthYearDate.data(), rx, "$5-$3-$1");