Bagaimana cara membagi string literal melintasi beberapa baris dalam C / Objective-C?

321

Saya memiliki permintaan sqlite yang cukup panjang:

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

Bagaimana saya bisa memecahnya dalam beberapa baris untuk membuatnya lebih mudah dibaca? Jika saya melakukan hal berikut:

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

Saya mendapatkan kesalahan.

Apakah ada cara untuk menulis kueri dalam beberapa baris?

Ilya Suzdalnitski
sumber

Jawaban:

569

Ada dua cara untuk membagi string pada beberapa baris:

Menggunakan \

Semua baris dalam C dapat dibagi menjadi beberapa baris menggunakan \.

Polos C:

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

Tujuan-C:

NSString *my_string = @"Line1 \
                        Line2";

Pendekatan yang lebih baik

Ada pendekatan yang lebih baik yang hanya berfungsi untuk string.

Polos C:

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

Tujuan-C:

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

Pendekatan kedua lebih baik, karena tidak ada banyak spasi yang dimasukkan. Namun untuk permintaan SQL, keduanya dimungkinkan.

CATATAN: Dengan #define, Anda harus menambahkan ekstra '\' untuk menyatukan dua string:

Polos C:

#define kMyString "Line 1"\
                  "Line 2"
Georg Schölly
sumber
22
Keduanya sama dengan di dan C dan C ++. Solusi yang terakhir lebih disukai karena yang pertama menanamkan banyak ruang putih yang tidak berguna ke dalam program yang juga akan ditransmisikan ke server DB.
Alnitak
Anda melewatkan @ pada awal baris 2 dalam contoh Objective-C yang lebih baik.
Lawrence Johnston
Apakah Anda memiliki tautan ke spec yang mendokumentasikan pilihan kedua @?
Perbatasan Heath
@HeathBorders: Tidak di sini, tapi saya sudah mencarinya ketika saya menulis jawabannya.
Georg Schölly
10
Keuntungan lain dari pendekatan yang lebih baik adalah, Anda dapat menempatkan // komentar setelah setiap baris.
fishinear
110

Ada trik yang bisa Anda lakukan dengan pre-processor.
Ini memiliki potensi sisi bawah bahwa itu akan runtuh ruang putih, dan bisa membingungkan bagi orang yang membaca kode.
Tapi, ada sisi baiknya sehingga Anda tidak perlu melarikan diri dari karakter kutipan di dalamnya.

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

preprocessor mengubahnya menjadi:

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

Saya telah menggunakan trik ini ketika saya sedang menulis beberapa unit test yang memiliki string literal besar yang berisi JSON. Itu berarti bahwa saya tidak harus melarikan diri dari setiap karakter kutipan \ ".

Nicholas Daley
sumber
5
Sempurna! Sekarang saya hanya perlu memberikan ini beberapa ratus upvote, dan mendapatkannya di tempatnya ...
Mike
Saya bereaksi dengan cara yang sama, tetapi ini bukan tanpa masalah. Saya baru saja mencoba melakukan heredoc dengan cara ini dengan karakter Unicode khusus dan mendapat kesalahan tentang karakter non-ASCII yang tidak diizinkan di luar literal.
philipkd
+1 tetapi untuk catatan saya mengalami masalah dengan kompiler (MSVC) atau editor (QtCreator) bukan (kembali) mengkompilasi ekspresi sebagaimana mestinya pada perubahan. Sepertinya perubahan tidak terdeteksi ... Memukul Rebuild alih-alih Build melakukan trik.
Andreas
Terima kasih atas informasi Nugget Ayam ini. Itu melakukan persis apa yang perlu saya lakukan tanpa semua sampah tambahan.
FishGuy876
Sayangnya ini tidak berfungsi jika Anda memiliki tanda kutip literal di string. Yah, itu semacam bekerja, karena menghasilkan peringatan. Tapi basis kode saya adalah -Werror ...
AnilRedshift
24

Anda juga bisa masuk ke XCode -> Preferences, pilih tab Indentation, dan aktifkan Line Wrapping.

Dengan begitu, Anda tidak perlu mengetikkan sesuatu yang ekstra, dan itu akan berfungsi untuk hal-hal yang sudah Anda tulis. :-)

Satu hal yang mengganggu adalah ...

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
sumber
2
@YoYoYonnY Saya setuju, tapi saya juga menghargainya. Saya terkejut bahwa komentar ini tidak akan benar-benar mungkin sebagai komentar, oleh karena itu penggunaan format jawaban. Ini tampaknya seperti batasan S / O, bahwa Anda tidak dapat menulis komentar yang sangat kaya (sejauh yang saya ketahui).
Max von Hippel
24

Saya mengalami masalah ini sepanjang waktu, jadi saya membuat alat kecil untuk mengonversi teks menjadi string Objective-C multi-line yang lolos:

http://multilineobjc.herokuapp.com/

Semoga ini menghemat waktu Anda.

Flaviu
sumber
1
alat hebat! pertanyaan: mengapa Anda lolos '|'?
justadreamer
Poin yang bagus. Saya mengubahnya untuk tidak lagi melarikan diri "|". Terima kasih telah memberi tahu saya.
Flaviu
Saya punya ide yang sama. Seandainya aku akan melihat ini dulu. Alat saya adalah: nsstringify.nateflink.com
Nate Flink
1
Terima kasih, menyelamatkan saya banyak waktu!
djskinner
Coba gunakan Format Dentang (terintegrasi dengan editor favorit Anda): clang.llvm.org/docs/ClangFormat.html
Ahmed Fasih
18

Memperluas ide Penawaran untuk Objective-C:

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

NSString *sql = NSStringMultiline(
    SELECT name, age
    FROM users
    WHERE loggedin = true
);
Berik
sumber
3
#define NSStringMultiline(...) @#__VA_ARGS__harus bekerja juga.
Nicholas Daley
Untuk string yang bisa berubah-ubah: #define NSStringMultiline(...) [[NSMutableString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]
rimsky
Bagi saya, string yang dihasilkan tidak memiliki baris baru.
rimsky
Baris baru yang diambil ditangkap dengan benar (yang tidak begitu nyaman atau menyenangkan).
rimsky
@rimsky, Dan saya pikir itu #define NSStringMultiline(...) [@#__VA_ARGS__ mutableCopy]juga berfungsi untuk string yang bisa berubah.
Iulian Onofrei
5

Satu lagi solusi untuk tumpukan, ubah file .m Anda menjadi .mm sehingga menjadi Objective-C ++ dan gunakan C ++ raw literals, seperti ini:

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

Literal mentah mengabaikan semuanya sampai urutan terminasi, yang dalam kasus default adalah kurung-kutipan.

Jika urutan kurung-kutipan harus muncul di string di suatu tempat, Anda juga dapat dengan mudah menentukan pemisah khusus, seperti ini:

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
sumber
Saya juga menemukan bahwa GCC menambahkan C ++ string literal baku sebagai ekstensi ke bahasa C: stackoverflow.com/questions/797318/…
Ciro Santilli 郝海东 冠状 病 六四 六四 事件 法轮功
3

Anda juga dapat melakukan:

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

GCC menambahkan C ++ multiline string string literal sebagai ekstensi C.

C ++ 11 memiliki literal string mentah seperti yang disebutkan di: https://stackoverflow.com/a/44337236/895245

Namun, GCC juga menambahkan mereka sebagai ekstensi C, Anda hanya perlu menggunakan -std=gnu99bukan -std=c99. Misalnya:

main.c

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

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

Kompilasi dan jalankan:

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

Ini dapat digunakan misalnya untuk memasukkan rakitan inline multiline ke dalam kode C: Bagaimana cara menulis kode rakitan inline multiline di GCC C ++?

Sekarang Anda hanya perlu berbaring, dan tunggu sampai standar di C20XY.

C ++ diminta di: C ++ string multiline literal

Diuji pada Ubuntu 16.04, GCC 6.4.0, binutils 2.26.1.

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

Alternatifnya adalah dengan menggunakan alat apa pun untuk menghapus jeda baris. Tulis string Anda menggunakan editor teks apa pun, setelah selesai, tempel teks Anda di sini dan salin lagi dalam xcode.

OUBERGHOUZ MOHAMED
sumber
1
Bukan solusi jangka panjang. Bagaimana jika Anda harus mengubahnya lagi nanti. Cepat, menjengkelkan, lebih baik menggunakan teknologi multi-jalur yang telah disebutkan dan memformatnya langsung di file.
Schwarzie2478