Abseil Tip 64 Raw 문자열 리터럴


title: “이번 주의 팁 #64: Raw 문자열 리터럴” layout: tips sidenav: side-nav-tips.html published: true permalink: tips/64 type: markdown order: “064” —

원래 totw/64로 2013-12-09에 게시됨

작성자: Titus Winters (titus@google.com)

2017-10-23 업데이트

빠른 링크: abseil.io/tips/64

"(?:\"(?:\\\\\"|[^\"])*\"|'(?:\\\\'|[^'])*')"; — 고양이가 키보드를 밟고 지나간 흔적일까요, 아니면 여우가 뭐라고 하는 걸까요… 사실, 실제 C++ 코드에서 발견된 지나치게 이스케이프된 정규 표현식입니다.

아마도 C++에서 이스케이프 문제 때문에 정규 표현식을 제대로 이해시키는 데 어려움을 겪은 경험이 있을 것입니다. 마찬가지로, Protobuf나 JSON 데이터를 텍스트 형태로 유닛 테스트에 삽입할 때 따옴표와 줄바꿈을 유지하는 데 짜증이 났을 수도 있습니다. 이스케이프 처리가 많이 필요할수록(심지어 여러 번 중첩된 이스케이프라면 더더욱), 코드의 가독성은 급격히 떨어집니다.

다행히도, C++11에서는 이러한 이스케이프 처리를 제거해 주는 새로운 기능이 추가되었습니다: 바로 raw 문자열 리터럴입니다.

Raw 문자열 리터럴 형식

Raw 문자열 리터럴은 다음과 같은 특별한 문법을 사용합니다:

R"tag(여기에 원하는 내용을 입력하세요)tag"

tag는 최대 16자의 문자열(빈 태그도 가능합니다)이며, "tag( 이후와 )tag" 사이에 있는 모든 문자는 문자열 리터럴의 내용으로 그대로 사용됩니다. tag에는 괄호, 백슬래시, 공백을 제외한 어떤 문자든 포함될 수 있습니다.

다음의 예를 비교해 보세요:

const char concert_17_raw[] =
    "id: 17\n"
    "artist: \"Beyonce\"\n"
    "date: \"Wed Oct 10 12:39:54 EDT 2012\"\n"
    "price_usd: 200\n";

대신에 raw 문자열 리터럴을 사용하면 다음과 같이 작성할 수 있습니다:

const char concert_17_raw[] = R"(
    id: 17
    artist: "Beyonce"
    date: "Wed Oct 10 12:39:54 EDT 2012"
    price_usd: 200)";

특별한 경우

들여쓰기 규칙과 raw 문자열 리터럴이 줄바꿈을 포함할 수 있다는 사실을 고려하면, raw 문자열 블록의 첫 번째 줄을 어떻게 들여쓸 것인지에 대해 고민하게 될 수 있습니다. Protobuf 텍스트는 공백을 무시하므로, 선행 줄바꿈을 추가하여(파서에서 무시됨) 문제를 피할 수 있지만, 모든 raw 문자열이 그렇게 관대하지는 않습니다.

문자열 안에 )"가 포함되어 닫는 구분자로 인식되지 않게 하려면, 비어 있지 않은 태그를 사용하는 것이 유용합니다:

std::string my_string = R"foo(This contains quoted parens "()")foo";

결론

Raw 문자열 리터럴은 대부분의 프로그래머에게 일상적으로 사용하는 도구는 아닙니다. 하지만 이 새로운 언어 기능을 잘 활용하면 가독성을 높일 수 있는 상황이 분명 존재합니다. 다음에 이스케이프를 두 번(\\) 해야 할지 네 번(\\\\) 해야 할지 고민하게 된다면, raw 문자열 리터럴을 대신 사용해 보세요. 독자들이 감사할 것입니다. 물론, 정규 표현식은 여전히 어려울 수 있지만요:

R"regexp((?:"(?:\\"|[^"])*"|'(?:\\'|[^'])*'))regexp";

reference

https://github.com/abseil/abseil.github.io/blob/master/_posts/2017-10-26-totw-64.md