Cadeia de caracteres multilinha C ++ literal

415

Existe alguma maneira de ter texto simples com várias linhas, literais constantes em C ++, à Perl? Talvez algum truque de análise de #includeum arquivo? Eu não consigo pensar em um, mas garoto, isso seria legal. Eu sei que será em C ++ 0x.

rlbond
fonte
1
Geralmente você não deseja incorporar literais de string no código. Para I18N e L10N, é preferível colocar literais de seqüência de caracteres em um arquivo de configuração carregado em tempo de execução.
Martin York
45
Existem casos suficientes em que colocar literais de cadeia no código não é um problema: se a cadeia não for usada para representá-la ao usuário; ou seja: instruções SQL, nomes de arquivos, nomes de chave do Registro, linhas de comando a ser executado, ...
mmmmmmmm
2
@ Martin: Ainda pode ser útil saber, no entanto. Eu fiz isso para quebrar regexs complexos, por exemplo.
Boojum

Respostas:

591

Bem ... Mais ou menos. O mais fácil é usar apenas o fato de que literais de string adjacentes são concatenados pelo 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.";

O recuo não importa, pois não está dentro das aspas.

Você também pode fazer isso, contanto que evite a nova linha incorporada. Não fazer isso, como minha primeira resposta, não compilará:

const char * text2 =
  "Aqui, por outro lado, eu fiquei louco \
e realmente deixar o literal abranger várias linhas, \
sem se preocupar em citar \ cada linha
conteúdo. Isso funciona, mas você não pode recuar. ";

Novamente, observe as barras invertidas no final de cada linha; elas devem estar imediatamente antes do final da linha; elas estão escapando da nova linha na fonte, para que tudo funcione como se a nova linha não estivesse lá. Você não recebe novas linhas na string nos locais em que havia barras invertidas. Com esse formulário, você obviamente não pode recuar o texto, pois o recuo se tornaria parte da string, exibindo-o em espaços aleatórios.

descontrair
fonte
3
Foi-me dito no passado que a primeira opção pode ser implementada, mas ainda não encontrei um compilador que não respeite essa sintaxe.
Jason Mock
28
@ Jason: não era necessariamente uma parte dos compiladores anteriores ao C89, mas é definido no C89 e, portanto, é suportado essencialmente em todos os lugares.
Jonathan Leffler
4
Além disso, se você realmente deseja que a string seja formatada em várias linhas no c ++ 98, substitua \ n o espaço final em cada fragmento de string entre aspas. Literais brutos em C ++ 11 ainda são os meus favoritos.
EMSR
3
@unwind Observe que a nova linha no final da linha de origem não faz parte da string, apenas é pulada. Se você deseja uma nova linha como parte da string, precisa ter \ n \ no final da linha.
Hyde
2
Há um erro desagradável no Microsoft Visual Studio. Se você usar barras invertidas no final das linhas, ele recuará automaticamente o texto dentro da string.
palota
408

No C ++ 11, você tem literais de cadeia bruta. Mais ou menos como o texto aqui em shell e linguagens de script como 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";

Todos os espaços e recuo e as novas linhas na sequência são preservados.

Eles também podem ser utf-8 | 16 | 32 ou wchar_t (com os prefixos comuns).

Devo salientar que a sequência de escape, V0G0N, não é realmente necessária aqui. Sua presença permitiria colocar) "dentro da string. Em outras palavras, eu poderia ter colocado

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

(observe aspas extras) e a sequência acima ainda estaria correta. Caso contrário, eu poderia muito bem ter usado

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

As parênteses dentro das aspas ainda são necessárias.

emsr
fonte
24
Isso é realmente o que eu quero, a capacidade de evitar aspas, barra invertida-Ns, escapes e ainda ter novas linhas aparecendo na string real. Isso é útil para código incorporado (por exemplo, shaders ou Lua). Infelizmente, ainda não estamos todos usando C ++ - 0x. :-(
mlepage 18/07/12
2
Eu estava considerando isso para scripts SQL e Python incorporados. Eu esperava por você, se talvez o gcc o deixasse passar no modo C ++ 98, mas, infelizmente, não.
EMSR
3
Estou mais acostumado a clang e gcc. Neste compiladores, você deve definir um sinalizador para C ++ 0x ou c ++ 11. Procurando em um site da MS, parece que eles ainda não têm literais em bruto. Eu entendo que a MS lançará novas atualizações do compilador mais rapidamente à medida que os recursos do C ++ forem implementados. Procure o CTP do Visual C ++ Compiler de novembro de 2012 [ microsoft.com/en-us/download/details.aspx?id=35515] para obter a borda mais recente.
EMSR
5
@rsethc Basta usar #if 0#endifpara comentar os blocos de código. Ninhos também.
bobbogo
1
Inspirado pelo poema de Vogon!
Thane Plummer
27

#define MULTILINE(...) #__VA_ARGS__
Consome tudo entre parênteses.
Substitui qualquer número de caracteres consecutivos de espaço em branco por um único espaço.

Zlatan Stanojević
fonte
1
Você pode adicionar \nse você precisar de novas linhas
Simon
Note que ` (and hence \ n ) is copied literally, but "` é convertido em \". Então, MULTILINE(1, "2" \3)produz "1, \"2\" \3".
Andreas Spindler
@AndreasSpindler As aspas e as barras invertidas são escapadas por barras adicionais (adicionais) desde que apareçam dentro de um token literal de sequência ou caractere. Não tenho certeza qual é o seu ponto. É ilegal ter uma cotação incomparável (dupla ou única), para que as contrações não funcionem, ou mesmo um número ímpar delas, o que provavelmente é a maior desvantagem. +1 de qualquer maneira. Os "programadores reais" sempre usam contrações em pares sem nenhuma linha nova, de modo que as aspas simples sejam equilibradas.
Potatoswatter
O ponto é que ele escreveu "consome tudo entre parênteses".
Andreas Spindler
25

Uma maneira provavelmente conveniente de inserir seqüências de várias linhas é usando macro. Isso só funciona se aspas e parênteses estiverem equilibrados e não contiver vírgulas de nível 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 com o gcc 4.6 ou g ++ 4.6, isso produz: [[Using this trick(,) you don't need to use quotes. Though newlines and multiple white spaces will be replaced by a single whitespace.]]

Observe que ,não pode estar na sequência, a menos que esteja entre parênteses ou aspas. Aspas simples são possíveis, mas cria avisos do compilador.

Editar: Como mencionado nos comentários, #define MULTI_LINE_STRING(...) #__VA_ARGS__permite o uso de ,.

bcmpinc
fonte
Para um projeto no qual eu queria incluir alguns trechos de código lua no c ++, acabei escrevendo um pequeno script python, no qual inseri as seqüências de linhas múltiplas e deixei que isso gerasse um arquivo de origem c ++.
21123 bcmpinc
Perfeito para mim, adicionando uma enorme string de lista flutuante de várias linhas a partir de um arquivo collada para teste de unidade. Não gostava de colocar aspas em todos os lugares, precisava de uma solução para copiar e colar.
Soylent Graham
7
Você pode usar #define MULTILINE(...) #__VA_ARGS__se quiser que sua string contenha vírgulas.
Simon
2
Observe que isso eliminará a maioria dos espaços em branco extras (incluindo all \ne \r), o que é útil para alguns casos e fatal para outros.
BCS
17

Você também pode fazer isso:

const char *longString = R""""(
This is 
a very 
long 
string
)"""";
Raydelto Hernandez
fonte
2
obrigado, isso é ótimo, funciona mesmo em C. obviamente, char longString[] = R""""( This is a very long string )""""; também funciona para mim.
struggling_learner
2
Isso inicia e termina a string com uma nova linha?
Tim MB
1
É uma literal de cadeia de caracteres bruta . Disponível desde C ++ 11.
Mikolasan 25/01
15

Você pode fazer isso:

const char *text = "This is my string it is "
     "very long";
Eric
fonte
Qual é a diferença da resposta do @ unbind?
Sisir 8/02
1
@Sisir Postei 2 minutos antes do desenrolar.
Eric
Desculpas por ter perdido essa parte. Meu +1
Sisir 08/02
10

Como uma onça de experiência vale uma tonelada de teoria, tentei um pequeno programa de teste 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 esse fragmento com cpp -P -std=c++11 filenamepara reproduzir.

O truque #__VA_ARGS__é que __VA_ARGS__não processa o separador de vírgulas. Então você pode passá-lo para o operador de stringing. Os espaços à esquerda e à direita são aparados e os espaços (incluindo novas linhas) entre as palavras são compactados em um único espaço. Os parênteses precisam ser equilibrados. Acho que essas deficiências explicam por que os designers do C ++ 11, apesar de tudo #__VA_ARGS__, viram a necessidade de literais de strings brutos.

Andreas Spindler
fonte
9

Apenas para elucidar um pouco o comentário do @ emsr na resposta do @ unbind, se alguém não tiver a sorte de ter um compilador C ++ 11 (por exemplo, GCC 4.2.1) e quiser incorporar as novas linhas na string (ou char * ou string de classe), pode-se escrever algo como isto:

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

Muito óbvio, é verdade, mas o breve comentário do @ emsr não me chamou atenção quando li isso pela primeira vez, então tive que descobrir isso sozinho. Felizmente, salvei outra pessoa por alguns minutos.

CXJ
fonte
-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";
user3635122
fonte
Adicione uma explicação à sua resposta e não apenas trechos de código
Geordie
-1

Opção 1. Usando a biblioteca de reforço, você pode declarar a sequência como abaixo

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

Opção 2. Se o boost não estiver disponível no seu projeto, você poderá usar std :: string_view () no C ++ moderno.

piyu2cool
fonte