C ++ многострочный строковый литерал - PullRequest
360 голосов
/ 16 июля 2009

Есть ли способ иметь многострочные обычные текстовые константы в C ++, как в Perl? Может быть, какая-то хитрость при разборе файла #include? Я не могу думать об этом, но мальчик, это было бы хорошо. Я знаю, что это будет в C ++ 0x.

Ответы [ 8 ]

523 голосов
/ 16 июля 2009

ну ... вроде. Проще всего использовать тот факт, что смежные строковые литералы объединяются компилятором:

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 =
  "Here, on the other hand, I've gone crazy \
and really let the literal span several lines, \
without bothering with quoting each line's \
content. This works, but you can't indent.";

Опять же, обратите внимание на эти обратные слеши в конце каждой строки, они должны быть непосредственно перед концом строки, они экранируют новую строку в источнике, чтобы все действовало так, как будто новой строки не было. Вы не получаете переводы строки в местах, где у вас были обратные слеши. С помощью этой формы вы, очевидно, не сможете сделать отступ в тексте, так как отступ станет частью строки и будет содержать случайные пробелы.

319 голосов
/ 28 марта 2011

В C ++ 11 у вас есть необработанные строковые литералы. Вроде как здесь текст в оболочках и языках сценариев, таких как 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 (с обычными префиксами).

Я должен указать, что escape-последовательность V0G0N здесь на самом деле не нужна. Его присутствие позволило бы поместить "внутри строки". Другими словами, я мог бы поставить

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

(обратите внимание на дополнительные кавычки) и приведенная выше строка все равно будет правильной. В противном случае я мог бы с таким же успехом использовать

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

Парены внутри цитат все еще нужны.

25 голосов
/ 12 января 2013

#define MULTILINE(...) #__VA_ARGS__
Потребляет все в скобках.
Заменяет любое количество последовательных пробельных символов на один пробел.

24 голосов
/ 03 апреля 2012

Вероятно, удобный способ ввода многострочных строк - использование макросов. Это работает, только если кавычки и круглые скобки сбалансированы и не содержат запятых «верхнего уровня»:

#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__ позволяет использовать ,.

12 голосов
/ 16 июля 2009

Вы можете просто сделать это:

const char *text = "This is my string it is "
     "very long";
9 голосов
/ 11 сентября 2013

Поскольку унция опыта стоит тонны теории, я попробовал небольшую тестовую программу для 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__, увидели необходимость в необработанных строковых литералах.

7 голосов
/ 16 января 2013

Просто чтобы немного пояснить комментарий @ emsr в ответе @ unwind, если кому-то не повезло иметь компилятор C ++ 11 (скажем, GCC 4.2.1), и кто-то хочет вставить строки в строку либо char *, либо string class), можно написать что-то вроде этого:

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 не выскочил на меня, когда я прочитал это в первый раз, поэтому мне пришлось открыть это для себя. Надеюсь, я спас кого-то еще несколько минут.

2 голосов
/ 15 апреля 2019

Вы также можете сделать это:

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