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.


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.


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.


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.


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 ,.


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


15

Você pode fazer isso:

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

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.


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.


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

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.