2009-07-16 10 views
306

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

+1

Как правило, вы не хотите вставлять строковые литералы в код. Для I18N и L10N предпочтительнее помещать строковые литералы в файл конфигурации, который загружается во время выполнения. –

+32

Существует достаточно случаев, когда размещение строковых литералов в код не является проблемой: если строка не используется для представления ее пользователю; то есть: инструкции SQL, имена файлов, имена ключей реестра, строки команд, которые должны быть выполнены, ... – mmmmmmmm

+1

@Martin: Однако все же полезно знать. Например, я сделал это, чтобы разбить сложные регулярные выражения. – Boojum

ответ

440

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

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

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

+2

Мне говорили в прошлом, что первый вариант может быть до реализации, однако мне еще предстоит найти компилятор, который не соблюдает этот синтаксис. –

+23

@Jason: он не обязательно был частью компиляторов pre-C89, но он определен на C89 и поэтому поддерживается практически везде. –

+3

Кроме того, если вы действительно хотите, чтобы строка, отформатированная на нескольких строках в C++ 98, просто заменила \ n на завершающее пространство на каждый цитируемый фрагмент строки. C++ 11 сырые литералы по-прежнему остаются моей любимой. – emsr

11

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

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

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

в круглых скобках только внутри кавычек по-прежнему необходимы.

+12

Это действительно то, что я хочу, способность избегать цитат, обратных косых черт, экранов и, тем не менее, появляются новые строки в реальной строке. Это удобно для встроенного кода (например, шейдеров или Lua). К сожалению, мы все еще не используем C++ - 0x. :-( – mlepage

+1

Я сам рассматривал это для встроенных скриптов SQL и Python. Я надеялся на ваше счастье, если, возможно, gcc разрешил бы ему проходить в режиме C++ 98, но, увы, нет. – emsr

+0

Это не компилируется для меня в Visual Studio 2012.Есть ли какие-либо вещи, которые должны быть установлены в проекте или файлах для включения? – jjxtra

19

вероятно удобный способ ввода строк многострочной помощи. Эта функция работает только MACRO, если котировки и круглые скобки сбалансированы, и он не содержит «верха уровня:

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

+0

Для проекта, в котором я хотел включить некоторые фрагменты кода lua в C++, я закончил писать небольшой скрипт python, в который я ввел многострочные строки, и пусть это сгенерирует исходный файл C++. – bcmpinc

+0

Идеально подходит для меня, добавив огромную многострочную строку с плавающей точкой из файла collada для модульного тестирования. Мне не нравилось размещать кавычки повсюду, мне нужно было скопировать и вставить решение. –

+5

Вы можете использовать '#define MULTILINE (...) #__ VA_ARGS__', если вы хотите, чтобы ваша строка содержала запятые. – Simon

22

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

+1

Вы можете добавить '\ n', если вам нужны строки новой строки – Simon

+0

Обратите внимание, что' \ '(и, следовательно,' \ n') копируется буквально, но '' 'преобразуется в' \ ''. Поэтому 'MULTILINE (1," 2 "\ 3)' дает '' 1, \ "2 \" \ 3 "'. –

+0

@AndreasSpindler Котировки и обратные косые черты сбрасываются (дополнительными) обратными косыми чертами до тех пор, пока они появляются внутри символа символа строки или символа. Не уверен, в чем дело. Нельзя иметь непревзойденную цитату (двойную или одиночную), поэтому сокращения не работают или нечетное число из них в любом случае, что, вероятно, является самым большим недостатком. +1 в любом случае. «Реальные программисты» всегда используют сокращения в парах без промежуточной новой строки, поэтому баланс одиночных кавычек. – Potatoswatter

4

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

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

9

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