Letterale stringa multilinea C ++


416

Esiste un modo per avere letterali costanti a più righe in C ++, alla Perl? Forse qualche trucco di analisi con l' #includeing di un file? Non riesco a pensarne uno, ma ragazzo, sarebbe carino. So che sarà in C ++ 0x.


1
Generalmente non si desidera incorporare valori letterali stringa nel codice. Per I18N e L10N è preferibile inserire valori letterali stringa in un file di configurazione che viene caricato in fase di esecuzione.
Martin York,

46
Ci sono abbastanza casi in cui inserire letterali di stringhe nel codice non è un problema: se la stringa non viene utilizzata per rappresentarla all'utente; vale a dire: istruzioni SQL, nomi di file, nomi di chiavi di registro, righe di comando da eseguire, ...
mmmmmmmm

2
@Martin: può essere comunque utile saperlo. L'ho fatto per spezzare regex complesse, per esempio.
Boojum,

Risposte:


591

Bene ... In un certo senso. Il più semplice è semplicemente usare il fatto che i letterali stringa adiacenti sono concatenati dal compilatore:

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

Il rientro non ha importanza, poiché non è racchiuso tra virgolette.

Puoi anche farlo, purché ti occupi di sfuggire alla newline incorporata. In caso contrario, come ha fatto la mia prima risposta, non verrà compilato:

const char * text2 =
  "Qui, invece, sono impazzito \
e lascia che letteralmente si estenda su più righe, \
senza preoccuparsi di citare ogni riga \
soddisfare. Funziona, ma non puoi rientrare. ";

Ancora una volta, nota quelle barre rovesciate alla fine di ogni riga, devono essere immediatamente prima della fine della riga, stanno scappando dalla nuova riga nella fonte, in modo che tutto si comporti come se la nuova riga non fosse lì. Non si ottengono newline nella stringa nei punti in cui si sono verificate barre rovesciate. Con questo modulo, ovviamente, non puoi indentare il testo poiché l'indentazione diventerebbe parte della stringa, confondendola con spazi casuali.


3
In passato mi è stato detto che la prima opzione può essere implementata, tuttavia devo ancora trovare un compilatore che non rispetti tale sintassi.
Jason Mock,

28
@Jason: non faceva necessariamente parte dei compilatori pre-C89, ma è definito in C89 e quindi è supportato essenzialmente ovunque.
Jonathan Leffler,

4
Inoltre, se vuoi davvero che la stringa sia formattata su più righe in c ++ 98, sostituisci \ n con lo spazio finale su ogni frammento di stringa tra virgolette. I letterali grezzi C ++ 11 sono ancora i miei preferiti.
emsr

3
@unwind Nota che newline alla fine della linea di origine non fa parte della stringa, ma viene semplicemente saltato. Se vuoi una nuova riga come parte della stringa, devi avere \ n \ alla fine della riga.
hyde,

2
C'è un brutto bug in Microsoft Visual Studio. Se si utilizzano barre rovesciate alla fine delle righe, il rientro automatico del testo all'interno della stringa.
palota,

409

In C ++ 11 hai letterali stringa grezzi. Un po 'come qui-testo in shell e linguaggi di script come Python, Perl e 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";

Tutti gli spazi, i rientri e le nuove righe nella stringa vengono conservati.

Questi possono anche essere utf-8 | 16 | 32 o wchar_t (con i soliti prefissi).

Vorrei sottolineare che la sequenza di escape, V0G0N, non è effettivamente necessaria qui. La sua presenza consentirebbe di inserire) "all'interno della stringa. In altre parole, avrei potuto mettere

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

(nota le virgolette extra) e la stringa sopra sarebbe ancora corretta. Altrimenti avrei potuto usare altrettanto bene

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

Le parentesi appena dentro le virgolette sono ancora necessarie.


24
Questo è davvero quello che voglio, la possibilità di evitare virgolette, barre rovesciate, N, escape e avere ancora delle righe visualizzate nella stringa attuale. Questo è utile per il codice incorporato (ad esempio shader o Lua). Sfortunatamente, non stiamo ancora usando tutti C ++ - 0x. :-(
mlepage

2
Lo stavo prendendo in considerazione per gli script SQL e Python incorporati. Speravo per il tuo bene se forse gcc lo avesse lasciato passare in modalità C ++ 98 ma, ahimè, no.
emsr

3
Sono più abituato a clang e gcc. In questo compilatore devi impostare un flag per C ++ 0xo c ++ 11. Nel sito Web di MS sembra che non abbiano ancora dei letterali grezzi. capisco che MS rilascerà nuovi aggiornamenti del compilatore più rapidamente man mano che le funzionalità C ++ verranno implementate. Cerca il CTP del compilatore Visual C ++ di novembre 2012 [ microsoft.com/en-us/download/details.aspx?id=35515] per il limite più recente.
emsr

5
@rsethc Basta usare #if 0... #endifper commentare blocchi di codice. Anche i nidi.
bobbogo,

1
Ispirato alla poesia di Vogon!
Thane Plummer,

27

#define MULTILINE(...) #__VA_ARGS__
Consuma tutto tra parentesi.
Sostituisce un numero qualsiasi di spazi bianchi consecutivi di un singolo spazio.


1
Puoi aggiungere \nse hai bisogno di nuove righe
Simon

Nota che ` (and hence \ n ) is copied literally, but "` viene convertito in \". Quindi MULTILINE(1, "2" \3)cede "1, \"2\" \3".
Andreas Spindler,

@AndreasSpindler Le citazioni e le barre rovesciate sono ugualmente sfuggite alle barre rovesciate (aggiuntive) purché appaiano all'interno di una stringa o di un token letterale di caratteri. Non sono sicuro di quale sia il tuo punto. È illegale avere una citazione senza eguali (doppia o singola), quindi le contrazioni non funzionano, o comunque un numero dispari di esse, che è probabilmente il più grande svantaggio. +1 comunque. I "veri programmatori" usano sempre le contrazioni in coppia senza interlinea nuova, quindi le singole virgolette si bilanciano.
Potatoswatter,

Il punto è che scrisse "consuma tutto tra parentesi".
Andreas Spindler,

25

Un modo probabilmente conveniente per inserire stringhe multilinea è usare le macro. Funziona solo se le virgolette e le parentesi sono bilanciate e non contiene virgole di "livello superiore":

#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);

Compilato con gcc 4.6 o g ++ 4.6, questo produce: [[Using this trick(,) you don't need to use quotes. Though newlines and multiple white spaces will be replaced by a single whitespace.]]

Nota che ,non può essere nella stringa, a meno che non sia racchiuso tra parentesi o virgolette. Le virgolette singole sono possibili, ma creano avvisi del compilatore.

Modifica: come menzionato nei commenti, #define MULTI_LINE_STRING(...) #__VA_ARGS__consente l'utilizzo di ,.


Per un progetto in cui volevo includere alcuni frammenti di codice lua in c ++, ho finito per scrivere un piccolo script Python, in cui ho inserito le stringhe multilinea e ho lasciato che generasse un file sorgente c ++.
bcmpinc,

Perfetto per me, aggiungendo un'enorme stringa float-list multilinea da un file collada per test unitari. Non mi andava di mettere le virgolette ovunque, avevo bisogno di una soluzione copia e incolla.
Soylent Graham,

7
È possibile utilizzare #define MULTILINE(...) #__VA_ARGS__se si desidera che la stringa contenga virgole.
Simon,

2
Nota che questo eliminerà la maggior parte dei bianchi (inclusi tutti \ne \r), il che è utile per alcuni casi e fatale per altri.
BCS


15

Puoi fare solo questo:

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

In che modo differisce dalla risposta di @ unwind?
Sisir,

1
@Sisir L'ho pubblicato 2 minuti prima di svolgermi.
Eric

Ci scusiamo per aver perso quella parte. Il mio +1
Sisir

10

Poiché un'oncia di esperienza vale un sacco di teoria, ho provato un piccolo programma di test per 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"
};

Compila questo frammento con cpp -P -std=c++11 filenameper riprodurre.

Il trucco dietro #__VA_ARGS__è che __VA_ARGS__non elabora il separatore di virgola. Quindi puoi passarlo all'operatore di stringere. Gli spazi iniziali e finali vengono tagliati e gli spazi (comprese le nuove linee) tra le parole vengono compressi in un unico spazio. Le parentesi devono essere bilanciate. Penso che queste carenze spieghino perché i progettisti di C ++ 11, nonostante #__VA_ARGS__, abbiano visto la necessità di letterali di stringa grezzi.


9

Giusto per chiarire un po 'il commento di @ emsr nella risposta di @ unwind, se uno non è abbastanza fortunato da avere un compilatore C ++ 11 (diciamo GCC 4.2.1), e si vuole incorporare le nuove righe nella stringa (o char * o stringa di classe), si può scrivere qualcosa del genere:

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

Molto ovvio, vero, ma il breve commento di @ emsr non è saltato fuori da me quando l'ho letto la prima volta, quindi ho dovuto scoprirlo da solo. Spero di aver salvato qualcun altro qualche minuto.


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

Aggiungi una spiegazione alla tua risposta e non solo i frammenti di codice
Geordie

-1

Opzione 1. Utilizzando la libreria boost, è possibile dichiarare la stringa come di seguito

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

Opzione 2. Se boost non è disponibile nel progetto, è possibile utilizzare std :: string_view () nel C ++ moderno.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.