본문 바로가기

MFC(Window Programming)

C++ 정규식과 Raw String Literal: 매칭과 사용법

728x90

 

 

C++ 정규식과 Raw String Literal: 매칭과 사용법

정규식을 사용하는 과정에서 가독성이나 사용 편의성을 높이기 위해 C++11부터 도입된 Raw String Literal이 유용하게 활용될 수 있습니다. 이번 포스팅에서는 C++에서 정규식을 활용하는 방법과 함께, Raw String Literal을 사용하는 이유에 대해 설명하고, 구체적인 예시를 통해 그 차이를 알아보겠습니다.

1. 정규식과 코드 예시

다음은 /home/user/test_script.sh 파일 경로가 포함된 문자열을 정규식으로 추출하는 예시입니다. 우선, 정규식을 사용하지 않고 문자열을 단순 비교하는 방법과, 정규식을 사용하는 방법에 대해 살펴보겠습니다.


#include <regex>
#include <iostream>
#include <string>

int main() {
    std::string input = R"(RUN+="/home/user/test_script.sh")";
    std::regex run_regex(R"(RUN\+=\s*\"([^\"]+)\")");

    std::smatch match;
    if (std::regex_search(input, match, run_regex)) {
        std::cout << "Matched Path: " << match[1] << std::endl;
    }

    return 0;
}
    

위 코드에서는 다음과 같은 부분을 중점적으로 살펴봐야 합니다:

  • 정규식: std::regex run_regex(R"(RUN\+=\s*\"([^\"]+)\")");
  • 이 정규식은 RUN+="으로 시작하고, 이어서 따옴표(") 안에 있는 파일 경로를 추출합니다.
  • RUN\+=: RUN+ 문자열과 = 기호가 나타납니다.
  • \s*: 그 뒤에 올 수 있는 공백을 0개 이상 허용합니다.
  • \"([^\"]+)\": 따옴표(")로 감싸진 문자열을 추출하며, 내부의 파일 경로는 캡처 그룹 ([^\"]+)로 추출됩니다.

2. Raw String Literal의 사용 이유

정규식 패턴을 다룰 때, C++의 일반적인 문자열 리터럴에서는 이스케이프 문자를 많이 사용해야 합니다. 예를 들어, 백슬래시(\)는 이스케이프 문자이기 때문에, 일반 문자열 리터럴에서는 다음과 같이 작성해야 합니다:

std::regex run_regex("RUN\\+=\\s*\"([^\"]+)\");

위 코드에서는 \ 문자를 두 번 써서 이스케이프 처리를 해야 하므로 가독성이 떨어집니다. 특히 복잡한 정규식을 사용할 때는 이러한 이스케이프 처리가 많아지며, 코드가 더 읽기 어려워집니다.

하지만, Raw String Literal을 사용하면 이러한 문제를 해결할 수 있습니다. R"(... )" 구문 안에서는 이스케이프 문자를 별도로 처리하지 않기 때문에, \도 있는 그대로 사용할 수 있습니다.

std::regex run_regex(R"(RUN\+=\s*\"([^\"]+)\")");

Raw String Literal을 사용하면 백슬래시를 이스케이프 할 필요가 없으므로 코드가 훨씬 간결해지고, 읽기 쉬워집니다.

3. 정규식 설명

위 코드에서 사용된 정규식의 각 요소를 좀 더 자세히 설명하겠습니다.

  • RUN+=: 이 부분은 RUN+이라는 문자열과 = 기호가 반드시 나타나야 함을 의미합니다. 정규식에서 +는 "하나 이상"을 의미하지만, 여기서는 실제로 + 문자가 패턴의 일부이므로 그대로 매칭됩니다.
  • \s*: 공백 문자(스페이스, 탭 등)를 0개 이상 허용합니다. 즉, = 기호 뒤에 공백이 있거나 없을 때 모두 일치합니다.
  • \": 따옴표(")를 찾습니다. C++의 일반 문자열에서 따옴표를 표시할 때는 이스케이프 문자(\)가 필요하기 때문에 \"로 표현됩니다. Raw String Literal에서는 그대로 " "을 사용할 수 있습니다.
  • ([^\"]+): 이 부분은 캡처 그룹입니다.
    [^\"]+는 "따옴표가 아닌 문자"를 의미하며, 하나 이상의 문자를 매칭합니다. 즉, 따옴표로 둘러싸인 문자열 안의 내용을 추출합니다.
  • 마지막 \": 문자열이 닫히는 따옴표입니다.

4. 자주 사용하는 정규식 기호

정규식에서는 다양한 기호를 통해 복잡한 문자열 패턴을 처리할 수 있습니다. 아래는 정규식에서 자주 사용하는 기호들과 그 의미를 표로 정리한 것입니다.

정규식 기호 설명 예시
. 임의의 한 문자(개행 문자 제외) a.bab 사이의 한 문자와 일치
^ 문자열의 시작을 의미 ^abc는 "abc"로 시작하는 문자열과 일치
$ 문자열의 끝을 의미 abc$는 "abc"로 끝나는 문자열과 일치
* 앞의 문자가 0회 이상 반복 a*는 "a"가 0회 이상 나타나는 문자열과 일치
+ 앞의 문자가 1회 이상 반복 a+는 "a"가 1회 이상 나타나는 문자열과 일치
? 앞의 문자가 0회 또는 1회 나타남 a?는 "a"가 없거나 1번 나타나는 문자열과 일치
\ 이스케이프 문자로, 특수 문자를 문자 그대로 사용 \\는 백슬래시 자체와 일치, \.는 마침표와 일치
| OR 연산자로 둘 중 하나와 일치 a|b는 "a" 또는 "b"와 일치
[] 문자의 집합(배열)을 정의 [abc]는 "a", "b", 또는 "c"와 일치
[^] 대괄호 안에 있는 문자를 제외한 모든 문자와 일치 [^abc]는 "a", "b", "c"를 제외한 모든 문자와 일치
() 그룹을 지정하고 캡처함 (abc)는 "abc"와 일치하며, 캡처 그룹으로 저장
{n} 정확히 n번 반복 a{3}는 "aaa"와 일치
{n,} 최소 n번 반복 a{2,}는 "aa", "aaa", "aaaa" 등과 일치
{n,m} 최소 n번, 최대 m번 반복 a{2,4}는 "aa", "aaa", "aaaa"와 일치
\d 숫자와 일치 (0-9) \d는 숫자와 일치
\D 숫자가 아닌 문자와 일치 \D는 숫자가 아닌 문자와 일치
\w 단어 문자를 의미 (알파벳, 숫자, 언더바) \w는 "a-z", "A-Z", "0-9", "_"와 일치
\W 단어 문자가 아닌 문자와 일치 \W는 단어 문자가 아닌 문자와 일치
\s 공백 문자(스페이스, 탭, 개행 등)와 일치 \s는 공백 문자와 일치
\S 공백 문자가 아닌 문자와 일치 \S는 공백 문자가 아닌 문자와 일치
(?=...) 전방 탐색(뒤에 오는 조건이 맞는지 확인, 패턴에 포함하지 않음) a(?=b)는 "ab"에서 "a"만 일치
(?!...) 부정 전방 탐색(뒤에 오는 조건이 없는 경우 일치) a(?!b)는 "ab"가 아닌 "a"와 일치

마무리

이번 포스팅에서는 C++에서 정규식을 사용하는 방법과 함께, Raw String Literal의 유용성에 대해 알아보았습니다. 특히, 정규식에서 백슬래시(\)와 같은 특수 문자를 처리하는 과정에서 Raw String Literal이 코드의 가독성을 크게 높일 수 있음을 확인할 수 있었습니다.

정리된 예시는 정규식 패턴을 이용하여 파일 경로를 쉽게 추출할 수 있는 좋은 방법을 제공합니다. Raw String Literal을 사용하면, 코드 작성과 유지보수가 더 쉬워지므로, 정규식을 자주 사용하는 개발자라면 적극 활용해 보시기 바랍니다!

728x90