C ++ багаторядковий літеральний рядок


415

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


1
Як правило, ви не хочете вставляти рядкові літерали в код. Для I18N та L10N бажано розміщувати рядкові літерали у файл конфігурації, який завантажується під час виконання.
Мартін Йорк

45
Існує достатньо випадків, коли введення рядкових літералів у код не є проблемою: якщо рядок не використовується для представлення її користувачеві; тобто: оператори SQL, імена файлів, імена ключів реєстру, командні рядки, які потрібно виконати, ...
mmmmmmmm

2
@Martin: Однак це все ще може бути корисно. Я зробив це, наприклад, для розбиття складних виразів.
Бужум

Відповіді:


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

407

У 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 (зі звичайними префіксами).

Я мушу зазначити, що послідовність аварійного виходу, V0G0N, насправді тут не потрібна. Його наявність дозволила б помістити "" всередині рядка. Іншими словами, я міг би поставити

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

(зверніть увагу на додаткові цитати), а рядок вище все ще буде правильним. Інакше я міг би так само добре використати

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

Парени, що знаходяться всередині цитат, все ще потрібні.


24
Це дійсно те, що я хочу, можливість уникати котирувань, зворотньої косої риски, епідемій і все ще мати нові рядки у фактичному рядку. Це зручно для вбудованого коду (наприклад, шейдери або Lua). На жаль, ми ще не використовуємо C ++ - 0x. :-(
mlepage

2
Я розглядав це для вбудованих сценаріїв SQL і Python. Я сподівався на вашу користь, якщо, можливо, gcc дозволить йому проскочити через режим C ++ 98, але, на жаль, ні.
emsr

3
Я більше звик до clang та gcc. У цьому компіляторі потрібно встановити прапор для C ++ 0x або c ++ 11. Подивіться на веб-сайт MS, схоже, у них ще немає сировинних літералів. Я розумію, що MS буде випускати нові оновлення компілятора швидше, коли функції C ++ будуть реалізовані. Шукайте Visual C ++ Compiler листопада 2012 року CTP [ microsoft.com/en-us/download/details.aspx?id=35515] для останнього кровотоку.
emsr

5
@rsethc Просто використовуйте #if 0#endifдля коментування блоків коду. Гнізда теж.
Боббого

1
Натхненний віршем "Вогон"!
Thane Plummer

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__дозволяє використовувати ,.


Для проекту, в якому я хотів включити деякі фрагменти коду lua в c ++, я закінчив написання невеликого сценарію python, в якому я ввів багаторядкові рядки, і дозволю, що генерує вихідний файл c ++.
bcmpinc

Ідеально підходить для мене, додавши величезний рядок з поплавковим списком з файлу колада для тестування одиниць. Я не хотів усюди ставити цитати, мені потрібно було рішення копіювати та вставляти.
Soylent Graham

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

Чим це відрізняється від відповіді @ unind?
Сисір

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 у відповіді @ unind, якщо одному не пощастило мати компілятор 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";

Будь ласка, додайте пояснення до своєї відповіді, а не лише фрагменти коду
Джорді

-1

Варіант 1. Використовуючи бібліотеку підвищення, ви можете оголосити рядок як показано нижче

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. Якщо підвищення у вашому проекті недоступне, ви можете використовувати std :: string_view () в сучасному C ++.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.