Як розділити літеральний рядок на кілька рядків у C / Objective-C?


320

У мене досить довгий запит sqlite:

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

Я отримую помилку.

Чи є спосіб написати запити в декількох рядках?

Відповіді:


568

Є два способи розділити рядки на кілька рядків:

Використовуючи \

Усі рядки в C можна розділити на кілька рядків за допомогою \.

Рівнина С:

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

Завдання-C:

NSString *my_string = @"Line1 \
                        Line2";

Кращий підхід

Є кращий підхід, який працює лише для струн.

Рівнина С:

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

Завдання-C:

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

Другий підхід кращий, оскільки тут не так багато пробілів. Однак для SQL-запиту можливі обидва.

ПРИМІТКА. За допомогою #define вам потрібно додати додатковий '\', щоб об'єднати два рядки:

Рівнина С:

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

22
Обидва такі ж, як і в C і C ++. Останнє рішення є кращим, оскільки перше вбудовує в програму багато непотрібного простору, який також буде переданий серверу БД.
Альнітак

Ви не вистачаєте на початку рядка 2 у кращому прикладі Objective-C.
Лоуренс Джонстон

Чи є у вас посилання на специфікацію, що документує необов'язковість другого @?
Гейт Межі

@HeathBorders: Тут не так, але я шукав це, коли писав відповідь.
Георг Шоллі

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
Ідеально! Тепер мені просто потрібно дати цьому ще кілька сотень оновлень і отримати її там, де належить ...
Майк

Я реагував так само, але це не без проблем. Я просто спробував зробити heredoc таким чином із спеціальним символом Unicode, і я отримав помилку про те, що символи, що не належать до ASCII, не дозволяються поза літералами.
philipkd

+1, але для запису у мене виникають проблеми з компілятором (MSVC) або редактором (QtCreator), який не (повторно) збирає вираз, як слід під час зміни. Це як зміни не виявлено ... Натискання Rebuild замість Build робить трюк.
Андреас

Дякую за цей курячий саморік інформації. Це робить саме те, що мені потрібно було робити без зайвого сміття.
FishGuy876

Це, на жаль, не працює, якщо у рядку у вас є буквальні лапки. Що ж, це працює, оскільки створює попередження. Але моя кодова база -Werror ...
AnilRedshift

24

Ви також можете зайти в XCode -> Налаштування, вибрати вкладку «Відступ» та увімкнути обертання ліній.

Таким чином, вам не доведеться набирати нічого зайвого, і це буде працювати для матеріалів, про які ви вже писали. :-)

Одна справа, що дратує ...

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, що ви не можете писати особливо насичені коментарі (наскільки мені відомо).
Макс фон Гіппель

24

У мене ця проблема постійно виникає, тому я створив крихітний інструмент для перетворення тексту в уникнуту багато рядкову рядок Objective-C:

http://multilineobjc.herokuapp.com/

Сподіваюсь, це заощадить певний час.


1
чудовий інструмент! питання: чому ти втечеш '|'?
justadreamer

Гарна думка. Я змінив його, щоб більше не бігти "|". Дякую, що повідомив.
Флавіу

У мене була така ж ідея. Бажаю, я б це бачив першим. Мій інструмент: nsstringify.nateflink.com
Nate Flink

1
Дякую, врятували мені багато часу!
djskinner

Спробуйте скористатися форматом Clang (інтегрується з улюбленими редакторами): clang.llvm.org/docs/ClangFormat.html
Ахмед Фасіх

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__також повинен працювати.
Ніколас Дейлі

Для змінних рядків: #define NSStringMultiline(...) [[NSMutableString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]
rimsky

Для мене в отриманому рядку немає нових рядків.
римський

Нові рядки, що уникнули, відображаються правильно (що майже не так зручно чи приємно).
rimsky

@rimsky, І я думаю, що це #define NSStringMultiline(...) [@#__VA_ARGS__ mutableCopy]також працює для змінних рядків.
Юліан Онофрей

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 / ...
Чіро Сантіллі郝海东冠状病六四事件法轮功

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 ++ multiline string literal

Тестовано на Ubuntu 16.04, GCC 6.4.0, бінулети 2.26.1.


0

Альтернативою є використання будь-якого інструменту для усунення розривів рядків. Напишіть рядок з допомогою будь-якого текстового редактора, як тільки ви закінчите, вставте текст тут і скопіювати його знову в Xcode.


1
Немає дійсно довгострокового рішення. Що робити, якщо вам доведеться це знову змінити пізніше. Швидко набридайте, краще скористайтеся вже згадуваними багаторядковими техніками та відформатуйте їх безпосередньо у файлі.
Schwarzie2478
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.