5

Как написать многострочную строку в языке программирования?

12

Заголовок: Многострочные литералы в C++ как в Perl

Тело вопроса: Есть ли способ задать многострочные текстовые литералы в C++, аналогично тому, как это делается в Perl? Возможно, существует какой-то прием с #include, который позволяет включить файл?

Я знаю, что начиная с C++11 можно использовать "сырые" строки, но интересует возможность делать это без использования сырых строк.

5 ответ(ов)

7

Ну... В общем, да. Самый простой способ — воспользоваться тем фактом, что соседние строковые литералы конкатенируются компилятором:

const char *text =
  "Этот текст довольно длинный, но будет "
  "конкатенирован в одну строку. "
  "Недостаток в том, что нужно заключать "
  "каждую часть в кавычки, а переносы строк "
  "должны быть как обычно.";

Отступы не имеют значения, так как они не находятся внутри кавычек.

Также вы можете сделать так, при условии, что вы правильно экранируете вложенные переносы строк. Неправильное экранирование, как в моем первом примере, приведет к ошибке компиляции:

const char *text2 =
  "Здесь, с другой стороны, я сошел с ума \
и действительно позволил литералу занимать несколько строк, \
не заботясь о кавычках для содержания каждой строки. Это работает, \
но вы не можете делать отступы.";

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

6

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

Следует отметить, что escape-последовательность V0G0N здесь не является обязательной. Однако её наличие позволяет использовать в строке символы )". Другими словами, я мог бы написать:

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

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

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

Скобки сразу внутри кавычек по-прежнему обязательны.

0

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

const char *longString = R""""(
Это 
очень 
длинная 
строка
)"""";

Использование сырого строкового литерала (raw string literal) позволяет легко записывать многострочные строки без необходимости заботиться о специальных символах или экранировании.

0

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

Как и любой другой макрос в C/C++, когда вы используете MULTILINE(...), он "поглощает" все, что находится между скобками. Оператор #__VA_ARGS__ превращает аргументы в строку, заключая их в кавычки.

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

На самом деле, в стандартном C/C++ нет встроенного способа для замены всех последовательных пробелов без перехода в более сложные манипуляции с строками. Вы можете реализовать эту логику в функции, которая будет обрабатывать строку после того, как она будет создана с помощью MULTILINE.

Пример использования макроса:

#include <stdio.h>

#define MULTILINE(...) #__VA_ARGS__

int main() {
    const char* str = MULTILINE(Hello,    World!       This is a test.); // "Hello,    World!       This is a test."
    printf("%s\n", str);
    return 0;
}

Для замены пробелов вы можете написать функцию, которая будет делать это, когда строка уже сформирована. Если вам нужна подобная функция, дайте знать!

0

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

#define MULTI_LINE_STRING(a) #a
const char *text = MULTI_LINE_STRING(
  Используя этот прием(,) вам не нужно использовать кавычки.
  Хотя переводы строк и     несколько     пробелов
  будут заменены на один пробел.
);
printf("[[%s]]\n",text);

При компиляции с gcc 4.6 или g++ 4.6 это дает следующий результат: [[Используя этот прием(,) вам не нужно использовать кавычки. Хотя переводы строк и несколько пробелов будут заменены на один пробел.]]

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

Правка: Как упомянуто в комментариях, использование #define MULTI_LINE_STRING(...) #__VA_ARGS__ позволяет использовать запятые.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь