Como dividir uma string literal em várias linhas em C / Objective-C?

321

Eu tenho uma consulta sqlite bastante longa:

const char *sql_query = "SELECT statuses.word_id FROM lang1_words, statuses WHERE statuses.word_id = lang1_words.word_id ORDER BY lang1_words.word ASC";

Como posso quebrá-lo em várias linhas para facilitar a leitura? Se eu fizer o seguinte:

const char *sql_query = "SELECT word_id
                        FROM table1, table2
                        WHERE table2.word_id = table1.word_id
                        ORDER BY table1.word ASC";

Estou recebendo um erro.

Existe uma maneira de escrever consultas em várias linhas?

Ilya Suzdalnitski
fonte

Respostas:

569

Há duas maneiras de dividir seqüências de caracteres em várias linhas:

Usando \

Todas as linhas em C podem ser divididas em várias linhas usando \.

C simples:

char *my_string = "Line 1 \
                   Line 2";

Objetivo-C:

NSString *my_string = @"Line1 \
                        Line2";

Melhor abordagem

Existe uma abordagem melhor que funciona apenas para strings.

C simples:

char *my_string = "Line 1 "
                  "Line 2";

Objetivo-C:

NSString *my_string = @"Line1 "
                       "Line2";    // the second @ is optional

A segunda abordagem é melhor, porque não há muito espaço em branco incluído. Para uma consulta SQL, no entanto, ambos são possíveis.

NOTA: Com um #define, você precisa adicionar um '\' extra para concatenar as duas strings:

C simples:

#define kMyString "Line 1"\
                  "Line 2"
Georg Schölly
fonte
22
Ambos são os mesmos que em e C e C ++. A última solução é preferida porque a primeira incorpora muito espaço em branco inútil no programa que também será transmitido ao servidor DB.
Alnitak
Você está faltando um @ no início da linha 2 no melhor exemplo de Objective-C.
Lawrence Johnston
Você tem um link para uma especificação que documenta a opcionalidade do segundo @?
Heath Borders
@HeathBorders: Não está aqui, mas eu procurei quando escrevi a resposta.
Georg Schölly
10
Outra vantagem da melhor abordagem é que você pode colocar // comentários após cada linha.
fishinear perto de
110

Há um truque que você pode fazer com o pré-processador.
Ele tem o potencial de reduzir o espaço em branco e pode ser confuso para as pessoas que leem o código.
Mas, tem o lado positivo de que você não precisa escapar de caracteres de aspas dentro dele.

#define QUOTE(...) #__VA_ARGS__
const char *sql_query = QUOTE(
    SELECT word_id
    FROM table1, table2
    WHERE table2.word_id = table1.word_id
    ORDER BY table1.word ASC
);

o pré-processador transforma isso em:

const char *sql_query = "SELECT word_id FROM table1, table2 WHERE table2.word_id = table1.word_id ORDER BY table1.word ASC";

Eu usei esse truque quando estava escrevendo alguns testes de unidade que tinham grandes seqüências literais contendo JSON. Isso significava que eu não precisava escapar de todos os caracteres de citação ".

Nicholas Daley
fonte
5
Perfeito! Agora eu só preciso dar uma mais algumas centenas de upvotes, e obtê-lo onde ele pertence ...
Mike
Eu estava reagindo da mesma maneira, mas isso não é sem problemas. Eu apenas tentei fazer um heredoc dessa maneira com um caractere Unicode especial e recebi um erro sobre caracteres não ASCII não serem permitidos fora dos literais.
philipkd
+1, mas para o registro, estou tendo problemas com o compilador (MSVC) ou o editor (QtCreator) não (re) compilando a expressão como deveria na alteração. É como se a mudança não fosse detectada ... Pressionar Rebuild ao invés de Build faz o truque.
Andreas
Obrigado por esta pepita de galinha de informações. Faz exatamente o que eu precisava fazer sem todo o lixo extra.
FishGuy876 23/08/19
Infelizmente, isso não funciona se você tiver aspas literais na string. Bem, isso meio que funciona, pois gera um aviso. Mas minha base de código é -Werror ...
AnilRedshift
24

Você também pode acessar XCode -> Preferences, selecionar a guia Indentation e ativar a quebra automática de linha.

Dessa forma, você não precisará digitar nada extra e isso funcionará para as coisas que você já escreveu. :-)

Uma coisa irritante é ...

if (you're long on indentation
    && short on windows) {
            then your code will
                end up squished
                     against th
                         e side
                             li
                              k
                              e

                              t
                              h
                              i
                              s
}
DenverCoder9
fonte
2
@YoYoYonnY Eu concordo, mas também aprecio isso. Parece-me que esse comentário não seria realmente possível como comentário, daí o uso do formato de resposta. Parece uma limitação de S / O, que você não pode escrever comentários particularmente ricos (pelo que sei).
Max von Hippel
24

Como estou com esse problema o tempo todo, criei uma pequena ferramenta para converter texto em uma string Objective-C de várias linhas de escape:

http://multilineobjc.herokuapp.com/

Espero que isso poupe algum tempo.

Flaviu
fonte
1
ótima ferramenta! pergunta: por que você escapa '|'?
Justadreamer
Bom ponto. Eu mudei para não mais escapar "|". Obrigado por me avisar.
Flaviu
Eu tive a mesma ideia. Gostaria de ter visto isso primeiro. Minha ferramenta é: nsstringify.nateflink.com
Nate Flink
1
Obrigado, me salvou muito tempo!
Djskinner
Tente usar o Clang Format (integra-se com seus editores favoritos): clang.llvm.org/docs/ClangFormat.html
Ahmed Fasih
18

Estendendo a ideia de cotação para o Objective-C:

#define NSStringMultiline(...) [[NSString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]

NSString *sql = NSStringMultiline(
    SELECT name, age
    FROM users
    WHERE loggedin = true
);
Berik
fonte
3
#define NSStringMultiline(...) @#__VA_ARGS__deve funcionar também.
Nicholas Daley
Para seqüências de caracteres mutáveis: #define NSStringMultiline(...) [[NSMutableString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]
rimsky 21/03/2015
Para mim, a sequência resultante não possui novas linhas.
rimsky
Novas linhas com escape são capturadas corretamente (o que não é tão conveniente ou agradável).
rimsky
@rimsky, e acho que isso #define NSStringMultiline(...) [@#__VA_ARGS__ mutableCopy]também funciona para strings mutáveis.
Iulian Onofrei
5

Mais uma solução para a pilha, altere seu arquivo .m para .mm para que ele se torne Objective-C ++ e use literais brutos em C ++, assim:

const char *sql_query = R"(SELECT word_id
                           FROM table1, table2
                           WHERE table2.word_id = table1.word_id
                           ORDER BY table1.word ASC)";

Literais brutos ignoram tudo até a sequência de finalização, que no caso padrão é aspas entre parênteses.

Se a sequência de aspas entre parênteses precisar aparecer na sequência em algum lugar, você também poderá especificar facilmente um delimitador personalizado, como este:

const char *sql_query = R"T3RM!N8(
                                  SELECT word_id
                                  FROM table1, table2
                                  WHERE table2.word_id = table1.word_id
                                  ORDER BY table1.word ASC
                         )T3RM!N8";
John Stephen
fonte
Eu também constatou que o GCC acrescenta C ++ strings literais-primas como uma extensão da linguagem C: stackoverflow.com/questions/797318/...
Ciro Santilli郝海东冠状病六四事件法轮功
3

Você também pode fazer:

NSString * query = @"SELECT * FROM foo "
                   @"WHERE "
                     @"bar = 42 "
                     @"AND baz = datetime() "
                   @"ORDER BY fizbit ASC";
Dave DeLong
fonte
2

O GCC adiciona literais de cadeia bruta multilinha em C ++ como uma extensão C

O C ++ 11 possui literais de cadeia bruta, conforme mencionado em: https://stackoverflow.com/a/44337236/895245

No entanto, o GCC também os adiciona como uma extensão C, basta usar em -std=gnu99vez de -std=c99. Por exemplo:

main.c

#include <assert.h>
#include <string.h>

int main(void) {
    assert(strcmp(R"(
a
b
)", "\na\nb\n") == 0);
}

Compile e execute:

gcc -o main -pedantic -std=gnu99 -Wall -Wextra main.c
./main

Isso pode ser usado, por exemplo, para inserir montagem em linha multilinha no código C: Como escrever código de montagem em linha multilinha no GCC C ++?

Agora basta recostar-se e aguardar que seja padronizado no C20XY.

O C ++ foi solicitado em: literal de cadeia de linhas multilinha do C ++

Testado no Ubuntu 16.04, GCC 6.4.0, binutils 2.26.1.

Ciro Santilli adicionou uma nova foto
fonte
0

Uma alternativa é usar qualquer ferramenta para remover quebras de linha. Escreva sua string usando qualquer editor de texto, depois de terminar, cole o texto aqui e copie-o novamente no xcode.

OUBERGHOUZ MOHAMED
fonte
1
Não é realmente uma solução a longo prazo. E se você precisar alterá-lo novamente mais tarde. Seja rápido, irritante, melhor usar as técnicas de várias linhas já mencionadas e formatá-lo diretamente no arquivo.
Schwarzie2478 6/02