【问题标题】:How to split a string literal across multiple lines in C / Objective-C?如何在 C / Objective-C 中将字符串文字拆分为多行?
【发布时间】:2010-10-22 06:58:50
【问题描述】:

我有一个很长的 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";

我收到一个错误。

有没有办法在多行中编写查询?

【问题讨论】:

    标签: c objective-c string-literals


    【解决方案1】:

    有两种方法可以将字符串拆分为多行:

    使用 \

    C 中的所有行都可以使用 \ 拆分为多行。

    普通 C:

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

    目标-C:

    NSString *my_string = @"Line1 \
                            Line2";
    

    更好的方法

    有一种更好的方法只适用于字符串。

    普通 C:

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

    目标-C:

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

    第二种方法更好,因为没有很多空格。然而,对于 SQL 查询,两者都是可能的。

    注意:使用#define,您必须添加一个额外的“\”来连接两个字符串:

    普通 C:

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

    【讨论】:

    • 这两个都和 C 和 C++ 中的一样。后一种解决方案是首选,因为前者在程序中嵌入了很多无用的空白区域,这些空白区域也将被传输到数据库服务器。
    • 在更好的 Objective-C 示例中,您在第 2 行的开头缺少了一个 @。
    • 您是否有指向规范的链接,该链接记录了第二个 @ 的可选性?
    • 更好方法的另一个优点是,您可以在每行之后放置 // cmets。
    • 第二种方法是否在两行之间插入\n\r\n
    【解决方案2】:

    预处理器有一个技巧。
    它有可能会折叠空白,并且可能会使阅读代码的人感到困惑。
    但是,它的好处是您不需要在其中转义引号字符。

    #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 的大型文字字符串的单元测试时使用了这个技巧。这意味着我不必转义每个引号字符 \"。

    【讨论】:

    • 完美!现在我只需要再给它几百个赞成票,然后把它放在它所属的地方......
    • 我的反应相同,但这并非没有问题。我刚刚尝试使用特殊的 Unicode 字符以这种方式做一个heredoc,并得到一个关于非ASCII字符不允许在文字之外的错误。
    • +1 但为了记录,我在编译器(MSVC)或编辑器(QtCreator)没有(重新)编译表达式时遇到问题,因为它应该改变。就像没有检测到更改...点击重建而不是构建就可以了。
    • 感谢您提供此鸡块信息。它完全符合我的需要,没有额外的垃圾。
    • 不幸的是,如果字符串中有文字引号,这将不起作用。嗯,它有点工作,因为它会产生一个警告。但我的代码库是 -Werror...
    【解决方案3】:

    您也可以进入 XCode -> Preferences,选择 Indentation 选项卡,然后打开 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
    }
    

    【讨论】:

    • @YoYoYonnY 我同意,但我也很感激。令我震惊的是,这条评论实际上不可能作为评论,因此使用了答案格式。这似乎是 S/O 的限制,您不能编写特别丰富的 cmets(据我所知)。
    【解决方案4】:

    我一直有这个问题,所以我做了一个小工具来将文本转换为转义的多行 Objective-C 字符串:

    http://multilineobjc.herokuapp.com/

    希望这可以为您节省一些时间。

    【讨论】:

    • 很棒的工具!问题:你为什么要逃避'|'?
    • 好点。我将其更改为不再转义“|”。谢谢你告诉我。
    • 我也有同样的想法。希望我能先看到这个。我的工具是:nsstringify.nateflink.com
    • 谢谢,节省了我很多时间!
    • 尝试使用 Clang 格式(与您最喜欢的编辑器集成):clang.llvm.org/docs/ClangFormat.html
    【解决方案5】:

    Quote 理念扩展到 Objective-C:

    #define NSStringMultiline(...) [[NSString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]
    
    NSString *sql = NSStringMultiline(
        SELECT name, age
        FROM users
        WHERE loggedin = true
    );
    

    【讨论】:

    • #define NSStringMultiline(...) @#__VA_ARGS__ 也应该可以工作。
    • 对于可变字符串:#define NSStringMultiline(...) [[NSMutableString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]
    • 对我来说,结果字符串没有新行。
    • 正确捕获转义的换行符(这不太方便或很好)。
    • @rimsky,我认为#define NSStringMultiline(...) [@#__VA_ARGS__ mutableCopy] 也适用于可变字符串。
    【解决方案6】:

    另一种解决方案,将您的 .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";
    

    【讨论】:

    【解决方案7】:

    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 代码中:How to write multiline inline assembly code in GCC C++?

    现在你只需要躺下,等待它在 C20XY 上标准化。

    C++ 被问到:C++ multiline string literal

    在 Ubuntu 16.04、GCC 6.4.0、binutils 2.26.1 上测试。

    【讨论】:

      【解决方案8】:

      你也可以这样做:

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

      【讨论】:

        【解决方案9】:

        另一种方法是使用任何工具来删除换行符。使用任何文本编辑器编写您的字符串,完成后,粘贴您的文本 here 并在 xcode 中再次复制。

        【讨论】:

        • 没有真正的长期解决方案。如果您以后必须再次更改它怎么办。烦人的快,最好使用已经提到的多行技术并直接在文件中格式化。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-07-03
        • 1970-01-01
        • 1970-01-01
        • 2011-01-15
        • 1970-01-01
        • 2012-01-30
        相关资源
        最近更新 更多