จะแยกสตริงตามตัวอักษรข้ามหลายบรรทัดใน C / Objective-C ได้อย่างไร?


321

ฉันมีแบบสอบถาม SQL ยาวสวย:

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

ฉันจะแบ่งเป็นหลายบรรทัดเพื่อให้อ่านง่ายขึ้นได้อย่างไร ถ้าฉันทำต่อไปนี้:

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

ฉันได้รับข้อผิดพลาด

มีวิธีเขียนแบบสอบถามหลายบรรทัดหรือไม่?

คำตอบ:


569

มีสองวิธีในการแบ่งสตริงผ่านหลายบรรทัด:

ใช้ \

บรรทัดทั้งหมดใน C สามารถแบ่งออกเป็นหลายบรรทัดโดยใช้ \

ธรรมดา C:

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

Objective-C:

NSString *my_string = @"Line1 \
                        Line2";

แนวทางที่ดีกว่า

มีวิธีที่ดีกว่าที่ใช้งานได้กับสตริง

ธรรมดา C:

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

Objective-C:

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

วิธีที่สองดีกว่าเนื่องจากไม่มีพื้นที่ว่างรวมอยู่มาก สำหรับการสืบค้น SQL อย่างไรก็ตามทั้งคู่เป็นไปได้

หมายเหตุ: ด้วย #define คุณจะต้องเพิ่มส่วนเสริม '\' เพื่อเชื่อมสองสายเข้าด้วยกัน:

ธรรมดา C:

#define kMyString "Line 1"\
                  "Line 2"

22
ทั้งสองอย่างนี้เหมือนกับในและ C และ C ++ วิธีการแก้ปัญหาหลังเป็นที่ต้องการเพราะหนึ่งในอดีตฝังจำนวนมากพื้นที่สีขาวไร้ประโยชน์ในโปรแกรมซึ่งจะถูกส่งไปยังเซิร์ฟเวอร์ฐานข้อมูล
Alnitak

คุณไม่มี @ ที่จุดเริ่มต้นของบรรทัด 2 ในตัวอย่าง Objective-C ที่ดีกว่า
ลอเรนซ์จอห์นสตัน

คุณมีลิงค์ไปยังข้อมูลจำเพาะเกี่ยวกับตัวเลือกของวินาที@หรือไม่?
Heath Borders

@HeathBorders: ไม่อยู่ที่นี่ แต่ฉันได้ค้นหามันเมื่อฉันเขียนคำตอบ
Georg Schölly

10
ข้อดีอีกอย่างของวิธีการที่ดีกว่าคือคุณสามารถใส่ // ความคิดเห็นหลังจากแต่ละบรรทัด
fishinear

110

มีเคล็ดลับที่คุณสามารถทำได้กับตัวประมวลผลล่วงหน้า
มีศักยภาพต่ำลงว่ามันจะยุบพื้นที่สีขาวและอาจสร้างความสับสนให้กับคนที่อ่านรหัส
แต่มันมีด้านที่คุณไม่จำเป็นต้องหลบเลี่ยงตัวละครที่อยู่ข้างใน

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

ตัวประมวลผลล่วงหน้าเปลี่ยนสิ่งนี้เป็น:

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

ฉันใช้เคล็ดลับนี้เมื่อฉันเขียนการทดสอบหน่วยที่มีสตริงตัวอักษรขนาดใหญ่ที่มี JSON มันหมายความว่าฉันไม่ต้องหลบหนีทุกตัวละครอ้าง \ "


5
ที่สมบูรณ์แบบ! ตอนนี้ผมเพียงต้องการที่จะให้นี้อีกไม่กี่ร้อย upvotes และได้รับมันที่มันเป็น ...
ไมค์

ฉันทำปฏิกิริยาในลักษณะเดียวกัน แต่นี่ไม่ใช่ปัญหา ฉันพยายามทำ heredoc ด้วยวิธีนี้เป็นอักขระ Unicode พิเศษและมีข้อผิดพลาดเกี่ยวกับอักขระที่ไม่ใช่ ASCII ที่ไม่ได้รับอนุญาตนอกตัวอักษร
philipkd

+1 แต่สำหรับระเบียนฉันมีปัญหากับคอมไพเลอร์ (MSVC) หรือตัวแก้ไข (QtCreator) ไม่ได้ (อีกครั้ง) รวบรวมการแสดงออกตามที่ควรจะเปลี่ยน มันเหมือนไม่มีการตรวจพบการเปลี่ยนแปลง ... การกดปุ่มสร้างใหม่แทนที่จะสร้างเป็นเคล็ดลับ
Andreas

ขอบคุณสำหรับข้อมูลนักเก็ตไก่คนนี้ มันทำสิ่งที่ฉันต้องทำโดยไม่ทิ้งขยะทั้งหมด
FishGuy876

น่าเสียดายที่นี่ใช้งานไม่ได้หากคุณมีเครื่องหมายอัญประกาศอยู่ในสตริง มันเป็นงานที่สร้างคำเตือน แต่ codebase ของฉันคือ
-Werror

24

คุณสามารถเข้าไปที่ XCode -> Preferences เลือกแท็บเยื้องและเปิด Line Wrapping

ด้วยวิธีนี้คุณจะไม่ต้องพิมพ์อะไรเพิ่มเติมและมันจะใช้ได้กับสิ่งที่คุณเขียนไปแล้ว :-)

สิ่งหนึ่งที่น่ารำคาญคือ ...

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
}

2
@YoYoYonnY ฉันเห็นด้วย แต่ฉันก็ชื่นชมเช่นกัน มันทำให้ฉันรู้สึกว่าความคิดเห็นนี้จะไม่สามารถเป็นความคิดเห็นได้อย่างแท้จริงดังนั้นการใช้รูปแบบคำตอบ ดูเหมือนว่าข้อ จำกัด ของ S / O ที่คุณไม่สามารถเขียนความเห็นที่หลากหลายโดยเฉพาะอย่างยิ่ง (เท่าที่ฉันทราบ)
Max von Hippel

24

ฉันมีปัญหานี้ตลอดเวลาดังนั้นฉันจึงสร้างเครื่องมือเล็ก ๆ เพื่อแปลงข้อความเป็นสตริง Objective-C แบบหลายบรรทัดที่หลบหนี:

http://multilineobjc.herokuapp.com/

หวังว่านี่จะช่วยคุณประหยัดเวลา


1
เครื่องมือที่ยอดเยี่ยม! คำถาม: ทำไมคุณถึงหลบหนี '|'
justadreamer

จุดดี. ฉันเปลี่ยนเป็นหนีไม่พ้น "|" ขอบคุณสำหรับการให้ฉันรู้ว่า.
Flaviu

ฉันมีความคิดเดียวกัน หวังว่าฉันจะได้เห็นสิ่งนี้ก่อน เครื่องมือของฉันคือ: nsstringify.nateflink.com
Nate Flink

1
ขอขอบคุณช่วยฉันประหยัดเวลาได้มาก!
djskinner

ลองใช้รูปแบบเสียงดังกราว (รวมเข้ากับบรรณาธิการที่คุณชื่นชอบ): clang.llvm.org/docs/ClangFormat.html
Ahmed Fasih

18

การขยายแนวคิดการเสนอราคาสำหรับ Objective-C:

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

NSString *sql = NSStringMultiline(
    SELECT name, age
    FROM users
    WHERE loggedin = true
);

3
#define NSStringMultiline(...) @#__VA_ARGS__ควรทำงานด้วย
นิโคลัส Daley

สำหรับสตริงที่ไม่แน่นอน: #define NSStringMultiline(...) [[NSMutableString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]
rimsky

สำหรับฉันสตริงผลลัพธ์ไม่มีบรรทัดใหม่
rimsky

มีการจับบรรทัดใหม่ที่หลบหนีอย่างถูกต้อง (ซึ่งไม่ค่อยสะดวกหรือดี)
rimsky

@rimsky และฉันคิดว่ามัน#define NSStringMultiline(...) [@#__VA_ARGS__ mutableCopy]ใช้ได้กับสตริงที่ไม่แน่นอนด้วย
Iulian Onofrei

5

อีกวิธีแก้ปัญหาสำหรับกองเปลี่ยนไฟล์. m ของคุณเป็น. mm เพื่อให้เป็น Objective-C ++ และใช้ตัวอักษรดิบ C ++ เช่นนี้

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

ตัวอักษรดิบจะละเว้นทุกอย่างจนกว่าลำดับการยกเลิกซึ่งในกรณีเริ่มต้นคือเครื่องหมายวงเล็บ

หากลำดับเครื่องหมายวงเล็บต้องปรากฏในสตริงที่ใดที่หนึ่งคุณสามารถระบุตัวคั่นแบบกำหนดเองได้เช่นกัน:

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

ฉันยังพบว่า GCC เพิ่มตัวอักษรสตริงสตริง C ++ เป็นส่วนเสริมสำหรับภาษา C: stackoverflow.com/questions/797318/…
Ciro Santilli 郝海东冠状病病六四事件法轮功

3

คุณยังสามารถทำสิ่งต่อไปนี้

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

2

GCC เพิ่มตัวอักษรสตริงสตริง C ++ หลายบรรทัดเป็นส่วนขยาย C

C ++ 11 มีตัวอักษรสตริงดิบตามที่ระบุไว้ที่: https://stackoverflow.com/a/44337236/895245

อย่างไรก็ตาม GCC ยังเพิ่มพวกเขาเป็นส่วนขยาย C, คุณเพียงแค่ต้องใช้แทน-std=gnu99 -std=c99เช่น:

main.c

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

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

รวบรวมและเรียกใช้:

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

สามารถใช้ตัวอย่างนี้เพื่อแทรกแอสเซมบลีแบบหลายบรรทัดใน C รหัส: วิธีการเขียนรหัสแอสเซมบลีแบบหลายบรรทัดใน GCC C ++

ตอนนี้คุณเพียงแค่ต้องเอนหลังและรอให้มันเป็นมาตรฐานใน C20XY

C ++ ถูกถามเมื่อ: C ++ หลายสตริงตัวอักษร

ทดสอบบน Ubuntu 16.04, GCC 6.4.0, binutils 2.26.1


0

อีกทางเลือกหนึ่งคือการใช้เครื่องมือใด ๆ สำหรับการลบตัวแบ่งบรรทัด เขียนสตริงของคุณโดยใช้เครื่องมือแก้ไขข้อความเมื่อเสร็จแล้วให้วางข้อความของคุณที่นี่และคัดลอกอีกครั้งใน xcode


1
ไม่มีทางออกระยะยาวจริงๆ ถ้าคุณต้องเปลี่ยนมันอีกครั้งในภายหลัง รับที่น่ารำคาญอย่างรวดเร็วดีกว่าที่จะใช้เทคนิคหลายสายที่กล่าวถึงแล้วและจัดรูปแบบได้โดยตรงในไฟล์
Schwarzie2478
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.