Wie teile ich ein String-Literal in C / Objective-C auf mehrere Zeilen auf?

319

Ich habe eine ziemlich lange SQLite-Abfrage:

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

Wie kann ich es in mehrere Zeilen aufteilen, um das Lesen zu erleichtern? Wenn ich folgendes mache:

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

Ich erhalte eine Fehlermeldung.

Gibt es eine Möglichkeit, Abfragen in mehreren Zeilen zu schreiben?

Ilya Suzdalnitski
quelle

Antworten:

568

Es gibt zwei Möglichkeiten, Zeichenfolgen auf mehrere Zeilen aufzuteilen:

Verwenden von \

Alle Zeilen in C können mit \ in mehrere Zeilen aufgeteilt werden.

Ebene C:

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

Ziel c:

NSString *my_string = @"Line1 \
                        Line2";

Besserer Ansatz

Es gibt einen besseren Ansatz, der nur für Zeichenfolgen funktioniert.

Ebene C:

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

Ziel c:

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

Der zweite Ansatz ist besser, da nicht viele Leerzeichen enthalten sind. Für eine SQL-Abfrage sind jedoch beide möglich.

HINWEIS: Bei einem #define müssen Sie ein zusätzliches '\' hinzufügen, um die beiden Zeichenfolgen zu verketten:

Ebene C:

#define kMyString "Line 1"\
                  "Line 2"
Georg Schölly
quelle
22
Beide sind dieselben wie in und C und C ++. Die letztere Lösung wird bevorzugt, da die erstere viel nutzlosen Leerraum in das Programm einbettet , der auch an den DB-Server übertragen wird.
Alnitak
Im besseren Objective-C-Beispiel fehlt am Anfang von Zeile 2 ein @.
Lawrence Johnston
Haben Sie einen Link zu einer Spezifikation, die die Optionalität der zweiten dokumentiert @?
Heath Borders
@HeathBorders: Nicht hier, aber ich habe es nachgeschlagen, als ich die Antwort schrieb.
Georg Schölly
10
Ein weiterer Vorteil des besseren Ansatzes besteht darin, dass Sie nach jeder Zeile // Kommentare einfügen können.
fishinear
110

Es gibt einen Trick, den Sie mit dem Vorprozessor machen können.
Es hat die potenziellen Nachteile, dass es den Leerraum kollabiert und für Leute, die den Code lesen, verwirrend sein kann.
Aber es hat den Vorteil, dass Sie sich nicht den Anführungszeichen entziehen müssen.

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

Der Präprozessor verwandelt dies in:

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

Ich habe diesen Trick verwendet, als ich einige Komponententests geschrieben habe, die große Literalzeichenfolgen mit JSON enthielten. Es bedeutete, dass ich nicht jedem Anführungszeichen entkommen musste.

Nicholas Daley
quelle
5
Perfekt! Jetzt muss ich nur noch ein paar hundert Upvotes geben und es dahin bringen, wo es hingehört ...
Mike
Ich habe genauso reagiert, aber das ist nicht ohne Probleme. Ich habe gerade versucht, auf diese Weise einen Heredoc mit einem speziellen Unicode-Zeichen zu erstellen, und habe eine Fehlermeldung erhalten, dass Nicht-ASCII-Zeichen außerhalb von Literalen nicht zulässig sind.
Philipkd
+1, aber für den Datensatz habe ich Probleme mit dem Compiler (MSVC) oder Editor (QtCreator), der den Ausdruck nicht (neu) kompiliert, wie er bei einer Änderung sein sollte. Es ist, als würde keine Änderung erkannt ... Wenn Sie Rebuild anstelle von Build treffen, reicht dies aus.
Andreas
Vielen Dank für dieses Chicken Nugget an Informationen. Es macht genau das, was ich tun musste, ohne all den zusätzlichen Müll.
FishGuy876
Wunderbar, aber können Sie das "\ n" zum Laufen bringen?
Sapphire_Brick
24

Sie können auch zu XCode -> Einstellungen gehen, die Registerkarte Einrückung auswählen und Zeilenumbruch aktivieren.

Auf diese Weise müssen Sie nichts extra eingeben, und es funktioniert für die Dinge, die Sie bereits geschrieben haben. :-)

Eine nervige Sache ist jedoch ...

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
quelle
2
@YoYoYonnY Ich stimme zu, aber ich schätze es auch. Es fällt mir auf, dass dieser Kommentar als Kommentar nicht wirklich möglich gewesen wäre, daher die Verwendung des Antwortformats. Dies scheint eine Einschränkung von S / O zu sein, da Sie keine besonders umfangreichen Kommentare schreiben können (soweit mir bekannt ist).
Max von Hippel
24

Ich habe die ganze Zeit dieses Problem, deshalb habe ich ein kleines Tool erstellt, um Text in eine maskierte mehrzeilige Objective-C-Zeichenfolge zu konvertieren:

http://multilineobjc.herokuapp.com/

Hoffe das spart dir etwas Zeit.

Flaviu
quelle
1
tolles Werkzeug! Frage: Warum entkommst du '|'?
Justadreamer
Guter Punkt. Ich habe es geändert, um nicht mehr "|" zu entkommen. Danke für die Information.
Flaviu
Ich hatte die gleiche Idee. Ich wünschte, ich hätte das zuerst gesehen. Mein Tool ist: nsstringify.nateflink.com
Nate Flink
1
Danke, hat mir viel Zeit gespart!
Djskinner
Versuchen Sie es mit dem Clang-Format (integriert in Ihre bevorzugten Editoren): clang.llvm.org/docs/ClangFormat.html
Ahmed Fasih
18

Erweiterung der Angebotsidee für Objective-C:

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

NSString *sql = NSStringMultiline(
    SELECT name, age
    FROM users
    WHERE loggedin = true
);
Berik
quelle
3
#define NSStringMultiline(...) @#__VA_ARGS__sollte auch funktionieren.
Nicholas Daley
Für veränderbare Saiten: #define NSStringMultiline(...) [[NSMutableString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]
Rimsky
Für mich hat die resultierende Zeichenfolge keine neuen Zeilen.
Rimsky
Entkommene Zeilenumbrüche werden korrekt erfasst (was bei weitem nicht so bequem oder nett ist).
Rimsky
@ Rimsky, und ich denke, das #define NSStringMultiline(...) [@#__VA_ARGS__ mutableCopy]funktioniert auch für veränderbare Strings.
Iulian Onofrei
5

Eine weitere Lösung für den Stapel: Ändern Sie Ihre .m-Datei in .mm, sodass sie zu Objective-C ++ wird, und verwenden Sie C ++ - Rohliterale wie folgt:

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

Rohe Literale ignorieren alles bis zur Beendigungssequenz, die im Standardfall in Klammern steht.

Wenn die Klammer-Anführungszeichen-Sequenz irgendwo in der Zeichenfolge erscheinen muss, können Sie auch einfach ein benutzerdefiniertes Trennzeichen angeben, wie folgt:

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
quelle
Ich habe auch festgestellt, dass GCC C ++ Raw-String-Literale als Erweiterung der C-Sprache hinzufügt
Ciro Santilli 7 冠状 病 六四 事件 法轮功
3

Sie können auch:

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

GCC fügt C ++ - mehrzeilige Raw-String-Literale als C-Erweiterung hinzu

C ++ 11 verfügt über Raw-String-Literale, wie unter https://stackoverflow.com/a/44337236/895245 beschrieben

GCC fügt sie jedoch auch als C-Erweiterung hinzu, die Sie nur -std=gnu99anstelle von verwenden müssen -std=c99. Z.B:

Haupt c

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

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

Kompilieren und ausführen:

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

Dies kann zum Beispiel verwendet werden, um mehrzeilige Inline-Assembly in C-Code einzufügen: Wie schreibe ich mehrzeiligen Inline-Assembly-Code in GCC C ++?

Jetzt müssen Sie sich nur noch zurücklehnen und warten, bis es auf C20XY standardisiert ist.

C ++ wurde gefragt bei: C ++ Multiline String Literal

Getestet unter Ubuntu 16.04, GCC 6.4.0, binutils 2.26.1.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
0

Eine Alternative besteht darin, ein beliebiges Werkzeug zum Entfernen von Zeilenumbrüchen zu verwenden. Schreiben Sie Ihre Zeichenfolge mit einem beliebigen Texteditor . Wenn Sie fertig sind, fügen Sie Ihren Text hier ein und kopieren Sie ihn erneut in xcode.

OUBERGHOUZ MOHAMED
quelle
1
Keine wirklich langfristige Lösung. Was ist, wenn Sie es später erneut ändern müssen? Es wird schnell nervig, besser die bereits erwähnten Mehrzeilentechniken zu verwenden und sie direkt in der Datei zu formatieren.
Schwarzie2478