Як розділити літеральний рядок на кілька рядків у 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.