Cómo escribir un literal de cadena de varias líneas
¿Hay alguna forma de tener literales constantes de texto plano de varias líneas en C++, al estilo Perl? ¿Quizás algún truco de análisis al #include
procesar un archivo?
Sé que puedes hacerlo con cadenas sin formato en C++11.
Especie de. Lo más fácil es simplemente usar el hecho de que el compilador concatena los literales de cadena adyacentes:
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.";
La sangría no importa, ya que no está entre comillas.
También puedes hacer esto, siempre y cuando tengas cuidado de evitar la nueva línea incrustada. De no hacerlo, como lo hizo mi primera respuesta, no se compilará:
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.";
Nuevamente, tenga en cuenta esas barras invertidas al final de cada línea, deben estar inmediatamente antes de que finalice la línea, escapan de la nueva línea en la fuente, para que todo actúe como si la nueva línea no estuviera allí. No aparecen nuevas líneas en la cadena en las ubicaciones donde tenía barras invertidas. Con este formulario, obviamente no puedes sangrar el texto ya que la sangría se convertiría en parte de la cadena, confundiéndola con espacios aleatorios.
En C++ 11 tienes literales de cadena sin formato. Algo así como texto aquí en shells y lenguajes de script como Python, Perl y 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";
Se conservan todos los espacios, sangrías y nuevas líneas de la cadena.
Estos también pueden ser utf-8|16|32 o wchar_t (con los prefijos habituales).
Debo señalar que la secuencia de escape, V0G0N, en realidad no es necesaria aquí. Su presencia permitiría poner )" dentro de la cadena. En otras palabras, podría haber puesto
"(by Prostetnic Vogon Jeltz; see p. 56/57)"
(tenga en cuenta las comillas adicionales) y la cadena anterior seguiría siendo correcta. De lo contrario, también podría haber usado
const char * vogon_poem = R"( ... )";
Los pares que se encuentran justo dentro de las comillas todavía son necesarios.
También puedes hacer esto:
const char *longString = R""""(
This is
a very
long
string
)"""";
#define MULTILINE(...) #__VA_ARGS__
Consume todo lo que está entre paréntesis.
Reemplaza cualquier número de espacios en blanco consecutivos por un solo espacio.
Una forma probablemente conveniente de ingresar cadenas de varias líneas es mediante el uso de macros. Esto sólo funciona si las comillas y los paréntesis están equilibrados y no contienen comas de "nivel superior":
#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);
Compilado con gcc 4.6 o g++ 4.6, esto produce:[[Using this trick(,) you don't need to use quotes. Though newlines and multiple white spaces will be replaced by a single whitespace.]]
Tenga en cuenta que ,
no puede estar en la cadena, a menos que esté entre paréntesis o comillas. Las comillas simples son posibles, pero crean advertencias del compilador.
Editar: Como se menciona en los comentarios, #define MULTI_LINE_STRING(...) #__VA_ARGS__
permite el uso de ,
.