C ++ многострочный строковый литерал

416

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

rlbond
источник
1
Как правило, вы не хотите встраивать строковые литералы в код. Для I18N и L10N предпочтительно помещать строковые литералы в файл конфигурации, который загружается во время выполнения.
Мартин Йорк,
46
Есть достаточно случаев, когда вставка строковых литералов в код не является проблемой: если строка не используется для представления ее пользователю; то есть: операторы SQL, имена файлов, имена разделов реестра, командные строки, которые должны быть выполнены, ...
мммммммм
2
@Martin: Это все еще может быть полезно знать, однако. Я сделал это, чтобы разбить сложные регулярные выражения, например.
Boojum

Ответы:

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 \ в конце строки.
Hyde
2
В Microsoft Visual Studio есть неприятная ошибка. Если вы используете обратную косую черту в конце строки, то она автоматически делает отступ в текст внутри строки.
Palota
409

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

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

EMSR
источник
24
Это действительно то, чего я хочу, - возможность избегать кавычек, обратной косой черты, экранировок, и все еще иметь переводы строк в текущей строке. Это удобно для встроенного кода (например, шейдеров или Lua). К сожалению, мы еще не все используем C ++ - 0x. :-(
mlepage
2
Я рассматривал это для встроенных сценариев SQL и Python самостоятельно. Ради тебя я надеялся, что, возможно, gcc пропустит его в режиме C ++ 98, но, увы, нет.
emsr
3
Я более привык к лязгу и gcc. В компиляторах thise вы должны установить флаг для C ++ 0x или c ++ 11. Посмотрите на веб-сайт MS, похоже, у них еще нет необработанных литералов. Я понимаю, что MS будет выпускать новые обновления компилятора быстрее по мере реализации функций C ++. Ищите компилятор Visual C ++, ноябрь 2012 г. CTP [ microsoft.com/en-us/download/details.aspx?id=35515] для получения информации о новейших технологиях.
emsr
5
@rsethc Просто используйте #if 0…, #endifчтобы закомментировать блоки кода. Гнезда тоже.
Боббого
1
Вдохновленный стихотворением Вогона!
Тейн Пламмер
27

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

Златан Станоевич
источник
1
Вы можете добавить, \nесли вам нужны новые строки
Симон
Обратите внимание, что ` (and hence \ n ) is copied literally, but "` конвертируется в \". Так что MULTILINE(1, "2" \3)получается "1, \"2\" \3".
Андреас Шпиндлер
@AndreasSpindler Кавычки и обратные косые черты экранируются (дополнительными) обратными косыми чертами, если они присутствуют внутри строкового или символьного литерального токена. Не уверен, в чем твоя точка зрения. Недопустимо иметь одинаковую кавычку (двойную или одинарную), поэтому сокращения не работают, или, во всяком случае, нечетное их количество, что, вероятно, является самым большим недостатком. +1 в любом случае. «Настоящие программисты» всегда используют сокращения в парах без вводной строки, поэтому баланс в одинарных кавычках.
Potatoswatter
Дело в том, что он написал «потребляет все в скобках».
Андреас Шпиндлер
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__позволяет использовать ,.

bcmpinc
источник
Для проекта, в который я хотел включить некоторые фрагменты кода lua в c ++, я в итоге написал небольшой скрипт на python, в котором я ввел многострочные строки и позволил генерировать исходный файл c ++.
bcmpinc
Идеально для меня, добавление огромной многострочной строки с плавающим списком из файла collada для модульного тестирования. Я не хотел ставить цитаты везде, мне нужно было решение для копирования и вставки.
Сойлент Грэм
7
Вы можете использовать, #define MULTILINE(...) #__VA_ARGS__если вы хотите, чтобы ваша строка содержала запятые.
Саймон
2
Обратите внимание, что это лишит большинство лишних пробелов (включая все \nи \r), что довольно удобно для некоторых случаев и фатально для других.
BCS
17

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

const char *longString = R""""(
This is 
a very 
long 
string
)"""";
Райделто Эрнандес
источник
2
спасибо, это здорово, работает даже в C. очевидно, char longString[] = R""""( This is a very long string )""""; работает и для меня.
struggling_learner
2
Это начало и конец строки с новой строкой?
Тим Мб
1
Это необработанный строковый литерал . Доступно с C ++ 11.
Миколасан
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 не выскочил на меня, когда я прочитал это в первый раз, поэтому мне пришлось открыть это для себя. Надеюсь, я спас кого-то еще несколько минут.

CXJ
источник
-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";
user3635122
источник
Пожалуйста, добавьте объяснение к вашему ответу, а не только фрагменты кода
Джорди
-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 не доступен в вашем проекте, вы можете использовать std :: string_view () в современном C ++.

piyu2cool
источник