Как разбить строковый литерал на несколько строк в 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 ++. Последнее решение является предпочтительным, поскольку первое встраивает много бесполезных пробелов в программу, которые также будут передаваться на сервер БД.
Альнитак,
Вы пропускаете @ в начале строки 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
}
DenverCoder9
источник
2
@YoYoYonnY Я согласен, но я также ценю это. Меня поражает, что этот комментарий не был бы по-настоящему возможен в качестве комментария, отсюда и использование формата ответа. Это похоже на ограничение S / O, что вы не можете писать особенно насыщенные комментарии (насколько я знаю).
Макс фон Хиппель
24

У меня постоянно возникает эта проблема, поэтому я создал крошечный инструмент для преобразования текста в экранированную многострочную строку Objective-C:

http://multilineobjc.herokuapp.com/

Надеюсь, это сэкономит вам время.

Flaviu
источник
1
отличный инструмент! вопрос: почему вы избегаете '|'?
justadreamer
Хорошая точка зрения. Я изменил его, чтобы больше не выходить "|". Спасибо, что дал мне знать.
Флавиу
У меня была такая же идея. Хотел бы я увидеть это первым. Мой инструмент: nsstringify.nateflink.com
Нейт Флинк,
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, и я думаю, что это #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/…
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