skip to content
Mehdi Mehdikhani
Table of Contents

Raw string literals in C++11 solve the escaping nightmare when working with regex patterns, file paths, JSON, or any string with lots of special characters.

What Raw String Literals Actually Are

Raw strings use R"(...)" syntax and don’t interpret escape sequences:

// Regular string - escape hell
std::string regex_pattern = "\\d{3}-\\d{2}-\\d{4}";
std::string windows_path = "C:\\Users\\John\\Documents\\file.txt";
// Raw string - clean and readable
std::string regex_pattern = R"(\d{3}-\d{2}-\d{4})";
std::string windows_path = R"(C:\Users\John\Documents\file.txt)";

Everything between the parentheses is taken literally.

Custom Delimiters

When your string contains )", you can use custom delimiters:

// This would break with regular R"(...)"
std::string code = R"cpp(
std::string msg = R"(Hello World)";
return msg;
)cpp";
// Custom delimiter "cpp" prevents conflicts

The delimiter can be any sequence of characters (up to 16), just make sure it doesn’t appear in your string.

When I Actually Use Raw Strings

Most of the time, I use raw strings for:

  1. Regular expressions: The most common use case:
#include <regex>
// Traditional string - hard to read
std::regex email_pattern("\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b");
// Raw string - much clearer
std::regex email_pattern(R"(\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b)");
// Complex regex patterns become manageable
std::regex url_pattern(R"(^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$)");
  1. Multi-line strings: JSON, SQL, HTML, etc.:
std::string json_template = R"({
"user": {
"name": "{{name}}",
"email": "{{email}}",
"settings": {
"theme": "dark",
"notifications": true
}
}
})";
std::string sql_query = R"(
SELECT u.name, u.email, p.title
FROM users u
JOIN posts p ON u.id = p.author_id
WHERE u.active = true
ORDER BY p.created_at DESC
LIMIT 10
)";
  1. File paths: Especially on Windows:
// Windows paths with raw strings
std::string config_path = R"(C:\Program Files\MyApp\config.ini)";
std::string data_folder = R"(\\server\shared\data)";
// Still useful for Unix paths with special characters
std::string script_path = R"(/usr/local/bin/process-data.sh)";
  1. Embedded code or markup: When embedding other languages:
std::string shader_code = R"glsl(
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
out vec3 vertexColor;
uniform mat4 transform;
void main() {
gl_Position = transform * vec4(aPos, 1.0);
vertexColor = aColor;
}
)glsl";
std::string html_template = R"html(
<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
<style>
body { font-family: "Helvetica Neue", sans-serif; }
</style>
</head>
<body>
<h1>{{heading}}</h1>
<p>{{content}}</p>
</body>
</html>
)html";

Real World Example

Here’s how I use raw strings in a configuration parser:

class ConfigParser {
private:
// Regex patterns for different config value types
static inline const std::regex string_pattern{R"("([^"\\]|\\.)*")"};
static inline const std::regex number_pattern{R"(-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)"};
static inline const std::regex boolean_pattern{R"(\b(?:true|false)\b)"};
static inline const std::regex array_pattern{R"(\[(?:\s*[^,\]]+(?:\s*,\s*[^,\]]+)*\s*)?\])"};
public:
void load_from_string(const std::string& config_text) {
// Parse configuration...
}
std::string get_default_config() const {
return R"config(
# Application Configuration
app_name = "MyApplication"
version = "1.0.0"
debug_mode = false
[database]
host = "localhost"
port = 5432
username = "admin"
password = "secret123"
connection_pool_size = 10
[logging]
level = "info"
file_path = "/var/log/myapp.log"
max_file_size = "10MB"
rotate_daily = true
[features]
enable_cache = true
cache_ttl_seconds = 3600
api_rate_limit = 1000
)config";
}
};

Combining with String Literals

Raw strings work with other string literal types:

// Wide character raw string
std::wstring wide_path = LR"(C:\Users\용호\Documents\파일.txt)";
// UTF-8 raw string
std::string utf8_text = u8R"(Héllo Wörld! 🌍)";
// UTF-16 raw string
std::u16string utf16_text = uR"(こんにちは世界)";

The Gotcha with Newlines

Raw strings preserve all whitespace, including newlines and indentation:

std::string indented = R"(
This line has leading spaces
This one too
)";
// indented starts with a newline and has spaces before each line
// If you don't want the leading newline:
std::string clean = R"(This line has no leading spaces
But this one might have trailing spaces
)";

The Pattern I Follow

I use raw strings whenever I have:

  • More than 2-3 escape sequences in a string
  • Multi-line content that needs to preserve formatting
  • Regular expressions of any complexity
  • File paths on Windows
  • Embedded code in another language
// Good candidates for raw strings
std::regex phone_pattern(R"(\(\d{3}\) \d{3}-\d{4})");
std::string json_config(R"({"key": "value"})");
std::string file_path(R"(C:\Program Files\App\data.txt)");
// Not worth it for simple cases
std::string simple = "Hello World"; // No escapes needed
std::string newline = "Line 1\nLine 2"; // Just one escape

Raw string literals are one of those simple features that make a huge difference in readability. Once you start using them, plain strings with escaped backslashes start to look like a chore.