C++ 多行字符串文字

Posted

技术标签:

【中文标题】C++ 多行字符串文字【英文标题】:C++ multiline string literal 【发布时间】:2010-11-11 06:33:17 【问题描述】:

有什么方法可以在 C++ 中使用多行纯文本常量文字,就像 Perl 一样?也许#includeing 文件的一些解析技巧?我想不出一个,但是男孩,那会很好。我知道它会在 C++0x 中。

【问题讨论】:

通常您不想将字符串文字嵌入到代码中。对于 I18N 和 L10N,最好将字符串文字放入在运行时加载的配置文件中。 有足够多的情况将字符串文字放入代码中不是问题:如果字符串不用于向用户表示它;即:SQL 语句、文件名、注册表项名称、要执行的命令行... @Martin:但是,知道它仍然很有用。例如,我这样做是为了分解复杂的正则表达式。 【参考方案1】:

嗯……有点。最简单的方法是使用编译器连接相邻字符串文字的事实:

const char *text =
  "This text is pretty long, but will be "
  "concatenated into just a single string. "
  "The disadvantage is that you have to quote "
  "each part, and newlines must be literal as "
  "usual.";

缩进无关紧要,因为它不在引号内。

您也可以这样做,只要您注意转义嵌入的换行符。如果不这样做,就像我的第一个答案一样,将无法编译:

常量字符 *text2 = “在这里,另一方面,我已经疯了\ 真的让文字跨越几行,\ 无需费心引用每一行的 \ 内容。这行得通,但你不能缩进。";

再次注意每行末尾的反斜杠,它们必须在行结束之前,它们正在转义源代码中的换行符,因此一切都好像换行符不存在一样。在有反斜杠的位置,字符串中不会出现换行符。使用这种形式,你显然不能缩进文本,因为缩进会成为字符串的一部分,用随机空格乱码。

【讨论】:

过去有人告诉我,第一个选项可以由实现决定,但是我还没有找到不支持该语法的编译器。 @Jason:它不一定是 C89 之前的编译器的一部分,但它是在 C89 中定义的,因此基本上在所有地方都受到支持。 另外,如果您真的希望在 c++98 中将字符串格式化为多行,只需将 \n 替换为每个带引号的字符串片段上的终止空间。 C++11 原始文字仍然是我的最爱。 @unwind 请注意,源代码行末尾的换行符不是字符串的一部分,它只是被跳过了。如果要将换行符作为字符串的一部分,则需要在行尾添加 \n\。 Microsoft Visual Studio 中存在严重的错误。如果在行尾使用反斜杠,它会自动缩进字符串中的文本。【参考方案2】:

在 C++11 中,您有原始字符串文字。有点像 shell 和脚本语言(如 Python、Perl 和 Ruby)中的 here-text。

const char * vogon_poem = R"V0G0N(
             O freddled gruntbuggly thy micturations are to me
                 As plured gabbleblochits on a lurgid bee.
              Groop, I implore thee my foonting turlingdromes.   
           And hooptiously drangle me with crinkly bindlewurdles,
Or I will rend thee in the gobberwarts with my blurlecruncheon, see if I don't.

                (by Prostetnic Vogon Jeltz; see p. 56/57)
)V0G0N";

保留字符串中的所有空格和缩进以及换行符。

这些也可以是 utf-8|16|32 或 wchar_t(带有通常的前缀)。

我应该指出,这里实际上不需要转义序列 V0G0N。它的存在将允许将 )" 放入字符串中。换句话说,我可以放入

                "(by Prostetnic Vogon Jeltz; see p. 56/57)"

(注意额外的引号)和上面的字符串仍然是正确的。否则我也可以使用

const char * vogon_poem = R"( ... )";

引号内的括号仍然需要。

【讨论】:

这真的是我想要的,能够避免引号、反斜杠-Ns、转义,并且在实际字符串中仍然出现换行符。这对于嵌入式代码(例如着色器或 Lua)很方便。不幸的是,我们还没有全部使用 C++-0x。 :-( 我自己正在考虑将这个用于嵌入式 SQL 和 Python 脚本。如果 gcc 可以让它在 C++98 模式下通过,我希望为你着想,但是,唉,不。 我比较习惯clang和gcc。在此编译器中,您必须为 C++0x 或 c++11 设置一个标志。看看一个 MS 网站,看起来他们还没有原始文字。我知道随着 C++ 功能的实现,MS 将更快地发布新的编译器更新。查找 Visual C++ 编译器 2012 年 11 月 CTP [microsoft.com/en-us/download/details.aspx?id=35515] 了解最新前沿。 @rsethc 只需使用#if 0 ... #endif 注释掉代码块。巢也。 我的多行字符串总是使用V0G0N,因为我永远记不住这个语法,所以我总是查找这个答案,然后我总是觉得很有趣。【参考方案3】:

您也可以这样做:

const char *longString = R""""(
This is 
a very 
long 
string
)"""";

【讨论】:

谢谢,这太棒了,甚至在 C 中也可以工作。显然,char longString[] = R""""( This is a very long string )""""; 对我也有效。 这是否以新行开始和结束字符串? 这是一个raw string literal。从 C++11 开始可用。 与 Arduino 一起工作!现在我可以轻松地提供嵌入式网页了! @emsr 的一个很好的变体表明他的答案看起来不像 PERL 而更像 Python。【参考方案4】:

#define MULTILINE(...) #__VA_ARGS__ 使用括号之间的所有内容。 用一个空格替换任意数量的连续空白字符。

【讨论】:

如果需要换行符可以加\n 请注意` (and hence \n) is copied literally, but "` 被转换为\"。所以MULTILINE(1, "2" \3) 产生"1, \"2\" \3" @AndreasSpindler 只要引号和反斜杠出现在字符串或字符文字标记内,它们就会被(附加)反斜杠转义。不知道你的意思是什么。有一个不匹配的引号(双引号或单引号)是非法的,所以收缩不起作用,或者无论如何都是奇数,这可能是最大的缺点。无论如何+1。 “真正的程序员”总是成对使用缩略词,中间没有换行符,因此单引号是平衡的。 关键是他写了“括号之间的东西”。【参考方案5】:

输入多行字符串的一种可能方便的方法是使用宏。这仅在引号和括号平衡且不包含“***”逗号时才有效:

#define MULTI_LINE_STRING(a) #a
const char *text = MULTI_LINE_STRING(
  Using this trick(,) you don't need to use quotes.
  Though newlines and     multiple     white   spaces
  will be replaced by a single whitespace.
);
printf("[[%s]]\n",text);

使用 gcc 4.6 或 g++ 4.6 编译,生成:[[Using this trick(,) you don't need to use quotes. Though newlines and multiple white spaces will be replaced by a single whitespace.]]

请注意,, 不能在字符串中,除非它包含在括号或引号中。可以使用单引号,但会产生编译器警告。

编辑:如 cmets 中所述,#define MULTI_LINE_STRING(...) #__VA_ARGS__ 允许使用 ,

【讨论】:

对于一个我想在 c++ 中包含一些 lua 代码 sn-ps 的项目,我最终编写了一个小的 python 脚本,在其中我输入了多行字符串,并让它生成一个 c++ 源代码文件。 非常适合我,从 collada 文件中添加一个巨大的多行浮动列表字符串以进行单元测试。我不想到处加上引号,我需要一个复制和粘贴解决方案。 如果你想让你的字符串包含逗号,你可以使用#define MULTILINE(...) #__VA_ARGS__ 请注意,这会去除大部分多余的空白(包括所有\n\r),这对某些情况很方便,但对另一些情况却是致命的。【参考方案6】:

你可以这样做:

const char *text = "This is my string it is "
     "very long";

【讨论】:

与@unwind 的回答有何不同? @Sisir 我在放松前 2 分钟发布了它。【参考方案7】:

只是为了澄清@emsr 在@unwind 的答案中的评论,如果一个人没有足够幸运拥有一个 C++11 编译器(比如 GCC 4.2.1),并且想要在字符串中嵌入换行符( char * 或类字符串),可以这样写:

const char *text =
  "This text is pretty long, but will be\n"
  "concatenated into just a single string.\n"
  "The disadvantage is that you have to quote\n"
  "each part, and newlines must be literal as\n"
  "usual.";

非常明显,是的,但是当我第一次阅读此内容时,@emsr 的简短评论并没有引起我的注意,因此我必须自己发现这一点。希望我已经救了别人几分钟。

【讨论】:

【参考方案8】:

由于一盎司的经验值得大量的理论,我为MULTILINE尝试了一个小测试程序:

#define MULTILINE(...) #__VA_ARGS__

const char *mstr[] =

    MULTILINE(1, 2, 3),       // "1, 2, 3"
    MULTILINE(1,2,3),         // "1,2,3"
    MULTILINE(1 , 2 , 3),     // "1 , 2 , 3"
    MULTILINE( 1 , 2 , 3 ),   // "1 , 2 , 3"
    MULTILINE((1,  2,  3)),   // "(1,  2,  3)"
    MULTILINE(1
              2
              3),             // "1 2 3"
    MULTILINE(1\n2\n3\n),     // "1\n2\n3\n"
    MULTILINE(1\n
              2\n
              3\n),           // "1\n 2\n 3\n"
    MULTILINE(1, "2" \3)      // "1, \"2\" \3"
;

cpp -P -std=c++11 filename编译这个片段来重现。

#__VA_ARGS__ 背后的技巧是__VA_ARGS__ 不处理逗号分隔符。因此,您可以将其传递给字符串化运算符。前导和尾随空格被修剪,然后单词之间的空格(包括换行符)被压缩为一个空格。括号需要平衡。我认为这些缺点解释了为什么 C++11 的设计者尽管有 #__VA_ARGS__,却看到了对原始字符串文字的需求。

【讨论】:

【参考方案9】:
// C++11. 
std::string index_html=R"html(
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>VIPSDK MONITOR</title>
    <meta http-equiv="refresh" content="10">
</head>
<style type="text/css">
</style>
</html>
)html";

【讨论】:

请在您的答案中添加解释,而不仅仅是代码 sn-ps【参考方案10】:

选项 1. 使用 boost 库,您可以将字符串声明如下

const boost::string_view helpText = "This is very long help text.\n"
      "Also more text is here\n"
      "And here\n"

// Pass help text here
setHelpText(helpText);

选项 2。如果您的项目中没有 boost 可用,您可以在现代 C++ 中使用 std::string_view()。

【讨论】:

以上是关于C++ 多行字符串文字的主要内容,如果未能解决你的问题,请参考以下文章

多行 C# 插值字符串文字

C#中的多行字符串文字

多行字符串的 JSON 和模板文字

如何在 C / Objective-C 中将字符串文字拆分为多行?

YAML中多行字符串的配置方法

C++输入多行数字到数组