C ++多行字符串文字


415

有什么方法可以在C ++中使用Perl编写多行纯文本,常量文字?也许解析#include文件有一些技巧?我想不出一个,但是男孩,那太好了。我知道它将用C ++ 0x。


1
通常,您不想将字符串文字嵌入代码中。对于I18N和L10N,最好将字符串文字放入运行时加载的配置文件中。
马丁·约克

45
在足够多的情况下,将字符串文字放入代码中不是问题:如果不使用字符串将字符串表示给用户;即:SQL语句,文件名,注册表项名称,要执行的命令行,...
mmmmmmmm

2
@马丁:但是,仍然有用。例如,我这样做是为了分解复杂的正则表达式。
Boojum,2009年

Answers:


591

好吧。最简单的方法是使用以下事实:相邻字符串文字由编译器连接:

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.";

缩进并不重要,因为它不在引号内。

只要您注意避开嵌入式换行符,也可以执行此操作。失败,就像我的第一个答案一样,将不会编译:

const char * text2 =
  “另一方面,我疯了\
并真正让文字跨越几行,
不用麻烦引用每一行的\
内容。这可行,但是您不能缩进。”

同样,请注意每行末尾的那些反斜杠,它们必须紧接在行末之前,它们在源代码中转义了换行符,以便所有内容都好像换行符不在那里。在反斜杠的位置,字符串中不会出现换行符。使用这种形式,您显然无法缩进文本,因为缩进将随后成为字符串的一部分,并在字符串中添加随机空格。


3
过去有人告诉我,第一个选项可以由实现决定,但是我还没有找到不支持该语法的编译器。
杰森·莫克

28
@Jason:它不一定是C89之前的编译器的一部分,但是它是在C89中定义的,因此基本上在任何地方都受支持。
乔纳森·莱夫勒

4
另外,如果您确实想要在c ++ 98中以多行格式设置的字符串,只需将\ n替换为每个引用的字符串片段上的终止空间。C ++ 11原始文字仍然是我的最爱。
emsr

3
@unwind请注意,源代码行末尾的换行符不是字符串的一部分,只是被跳过了。如果要将换行符作为字符串的一部分,则需要在行末使用\ n \。
海德

2
Microsoft Visual Studio中有一个讨厌的错误。如果在行尾使用反斜杠,则它将自动缩进字符串内的文本。
palota 2014年

406

在C ++ 11中,您具有原始字符串文字。shell和脚本语言(例如Python,Perl和Ruby)中的此处文本有点类似。

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"( ... )";

仍然需要引号内的括号。


23
这确实是我想要的,能够避免在实际字符串中出现引号,反斜杠-N,转义以及仍然有换行符。这对于嵌入式代码(例如,着色器或Lua)很方便。不幸的是,我们还没有全部使用C ++-0x。:-(
mlepage

2
我本人正在考虑将其用于嵌入式SQL和Python脚本。我希望为您着想,也许gcc会让它在C ++ 98模式下通过,但是,las,不是。
emsr

3
我更习惯于clang和gcc。在此编译器中,您必须为C ++ 0x或c ++ 11设置一个标志。在MS网站上查找,看来他们还没有原始文字。我了解随着C ++功能的实现,MS将更快地发布新的编译器更新。寻找Visual C ++编译器2012年11月CTP [ microsoft.com/en-us/download/details.aspx?id=35515]以获取最新的最新进展。
emsr

5
@rsethc只需使用#if 0#endif注释掉代码块即可。也筑巢。
bobbogo

1
受Vogon诗启发!
塔那·普鲁默

27

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


1
\n如果需要换行,可以添加
Simon

请注意,` (and hence \ n ) is copied literally, but “`转换成\"左右。MULTILINE(1, "2" \3)产量"1, \"2\" \3"
安德烈亚斯·斯平德勒

@AndreasSpindler只要引号和反斜杠出现在字符串或字符文字标记中,它们就会被(附加)反斜杠转义。不确定您的意思是什么。带有不匹配的报价(双精度或单精度)是非法的,因此收缩无效,或者无论如何收缩的数量都是奇数,这可能是最大的缺点。还是+1。“真正的程序员”始终使用成对的紧缩词,而中间没有换行符,因此单引号会保持平衡。
Potatoswatter

关键是他写了“消耗括号之间的所有内容”。
Andreas Spindler

25

输入多行字符串的一种可能方便的方法是使用宏。仅当引号和括号之间是平衡的并且不包含“顶级”逗号时,此方法才有效:

#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.]]

注意,,除非包含在括号或引号中,否则不能在字符串中。单引号是可能的,但是会产生编译器警告。

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


对于一个我想在C ++中包含一些lua代码段的项目,我最终编写了一个小python脚本,在其中输入了多行字符串,然后生成了c ++源文件。
bcmpinc 2012年

非常适合我,从collada文件中添加一个巨大的多行浮动列表字符串以进行单元测试。我不喜欢到处都加引号,我需要一个复制粘贴解决方案。
Soylent Graham

7
#define MULTILINE(...) #__VA_ARGS__如果希望字符串包含逗号,则可以使用。
西蒙(Simon)

2
请注意,这会去除掉大多数多余的空白(包括all \n\r),这在某些情况下是很方便的,而在另一些情况下是致命的。
BCS


15

您可以这样做:

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

与@unwind的答案有什么不同?
西西尔

1
@Sisir我在放松前2分钟发布了它。
埃里克

抱歉缺少该部分。我的+1
西西尔

10

由于一盎司的经验值得大量理论研究,因此我尝试了以下测试程序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

只是为了阐明@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的简短评论并没有引起我的注意,因此我必须自己发现这一点。希望我已经节省了别人几分钟。


-1
// 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";

请为您的答案添加说明,而不仅仅是代码段
Geordie

-1

选项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()。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.