C++ multilínea cadena literal
* c++ (7)
Dado que una onza de experiencia vale una tonelada de teoría, probé un pequeño programa de prueba para 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"
};
Compile este fragmento con cpp -P -std=c++11 filename
para reproducirlo.
El truco detrás de #__VA_ARGS__
es que __VA_ARGS__
no procesa el separador de coma. Así que puedes pasarlo al operador de encordado. Los espacios iniciales y finales se recortan, y los espacios (incluidas las nuevas líneas) entre las palabras se comprimen en un solo espacio en ese momento. Los paréntesis necesitan ser equilibrados. Creo que estas deficiencias explican por qué los diseñadores de C ++ 11, a pesar de #__VA_ARGS__
, vieron la necesidad de literales de cadena en bruto.
¿Hay alguna forma de tener literales constantes de texto sin formato de varias líneas en C ++, à la Perl? Tal vez algún truco de análisis con #include
un archivo? No puedo pensar en uno, pero muchacho, eso sería bueno. Sé que estará en C ++ 0x.
En C ++ 11 tienes literales crudos. Más o menos como aquí: texto 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";
Todos los espacios y sangría y las nuevas líneas en la cadena se conservan.
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, no es realmente necesaria aquí. Su presencia permitiría poner) "dentro de la cuerda. En otras palabras, podría haber puesto
"(by Prostetnic Vogon Jeltz; see p. 56/57)"
(tenga en cuenta las citas adicionales) y la cadena de arriba aún sería correcta. De lo contrario podría haber utilizado
const char * vogon_poem = R"( ... )";
Todavía se necesitan los parens dentro de las comillas.
Especie de. Lo más fácil es usar el hecho de que los compiladores literales de cadenas adyacentes están concatenados por el compilador:
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á dentro de las comillas.
También puede hacer esto, siempre y cuando tenga cuidado de escapar de la nueva línea incorporada. 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 las barras invertidas al final de cada línea, deben estar inmediatamente antes de que la línea termine, están escapando de la nueva línea en la fuente, de modo que todo actúe como si la nueva línea no estuviera allí. No obtiene nuevas líneas en la cadena en las ubicaciones donde tuvo barras invertidas. Con esta forma, obviamente no puede sangrar el texto ya que la sangría se convertiría en parte de la cadena, haciéndolo con espacios aleatorios.
Solo para dilucidar un poco sobre el comentario de @emsr en la respuesta de @ unwind, si uno no es lo suficientemente afortunado como para tener un compilador C ++ 11 (digamos GCC 4.2.1), y uno quiere incrustar las nuevas líneas en la cadena (cualquiera de los dos caracteres * o cadena de clase), uno puede escribir algo como esto:
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.";
Muy obvio, es cierto, pero el breve comentario de @emsr no me llamó la atención cuando lo leí por primera vez, así que tuve que descubrirlo por mí mismo. Con suerte, he salvado a alguien más unos minutos.
Solo puedes hacer esto:
const char *text = "This is my string it is "
"very long";
Una forma probablemente conveniente de ingresar cadenas de varias líneas es mediante el uso de macros. Esto solo funciona si las comillas y los paréntesis están equilibrados y no contiene 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.]]
[[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 crea advertencias del compilador.
Edit: Como se menciona en los comentarios, #define MULTI_LINE_STRING(...) #__VA_ARGS__
permite el uso de #define MULTI_LINE_STRING(...) #__VA_ARGS__
#define MULTILINE(...) #__VA_ARGS__
Consume todo entre los paréntesis.
Reemplaza cualquier número de caracteres de espacio en blanco consecutivos por un solo espacio.