C / Objective-Cで文字列リテラルを複数の行に分割する方法は?


321

私はかなり長い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";

エラーが発生します。

クエリを複数行で書く方法はありますか?

回答:


569

文字列を複数の行に分割する方法は2つあります。

\を使用する

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

2つ目のアプローチは、空白があまり含まれていないため、より優れています。ただし、SQLクエリの場合、両方が可能です。

注:#defineでは、2つの文字列を連結するために追加の「\」を追加する必要があります。

プレーンC:

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

22
これらはどちらも、CおよびC ++と同じです。前者は、DBサーバーに送信されるプログラムに多くの不要な空白を埋め込むため、後者のソリューションが推奨されます。
アルニタク

より良いObjective-Cの例では、2行目の先頭に@がありません。
ローレンスジョンストン

2番目のオプションを文書化した仕様へのリンクはあり@ますか?
Heath Borders

@HeathBorders:ここではありませんが、答えを書いたときに調べました。
GeorgSchölly12年

10
より良いアプローチのもう1つの利点は、各行の後に//コメントを付けることができることです。
2013

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
パーフェクト!今、私はこれに数百の賛成票を与え、それが属する場所でそれを取得する必要があるだけです...
マイク

私は同じように反応していましたが、これは問題がないわけではありません。この方法で特殊なUnicode文字を使用してヒアドキュメントを作成しようとしたところ、非ASCII文字がリテラルの外では許可されないというエラーが発生しました。
philipkd 2017年

+1しかし、記録のために、コンパイラー(MSVC)またはエディター(QtCreator)で問題が発生し、変更時に式を(再)コンパイルしません。変更が検出されないようなものです...ビルドの代わりにリビルドを押すとうまくいきます。
アンドレアス

チキンナゲットの情報をありがとうございます。それは私が余計なゴミを一切使わずに私がする必要があることを正確に行います。
FishGuy876

文字列にリテラルの引用符がある場合、残念ながらこれは機能しません。まあ、それは一種の働きで、警告を生成します。しかし、私のコードベースは-Werror ...です
AnilRedshift

24

XCode-> Preferencesに移動し、Indentationタブを選択して、Line Wrappingをオンにすることもできます。

そうすれば、余計なことを入力する必要がなくなり、すでに書いたものでも機能します。:-)

しかし、迷惑なことの1つは...

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 2016

24

私は常にこの問題を抱えているため、テキストをエスケープされた複数行のObjective-C文字列に変換する小さなツールを作成しました。

http://multilineobjc.herokuapp.com/

これにより時間を節約できることを願っています。


1
素晴らしいツール!質問:なぜ '|'をエスケープするのですか?
justadreamer

いい視点ね。「|」をエスケープしないように変更しました。知らせてくれてありがとうございます。
Flaviu

私も同じ考えでした。私が最初にこれを見ていたと思います。私のツールは:nsstringify.nateflink.com
Nate Flink

1
おかげで、時間を大幅に節約できました。
djskinner 2013年

Clang形式を使用してみてください(お気に入りのエディターと統合):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__も動作するはずです。
Nicholas Daley、2015年

可変文字列の場合: #define NSStringMultiline(...) [[NSMutableString alloc] initWithCString:#__VA_ARGS__ encoding:NSUTF8StringEncoding]
rimsky

私にとって、結果の文字列には改行がありません。
rimsky 2015年

エスケープされた改行は正しくキャプチャされます(これは、あまり便利でもなく便利でもありません)。
rimsky 2015年

@rimsky、それ#define NSStringMultiline(...) [@#__VA_ARGS__ mutableCopy]は可変文字列でも機能すると思います。
Iulian Onofrei 2016

5

パイルのもう1つの解決策は、.mファイルを.mmに変更して、Objective-C ++になるようにし、次のようにC ++のrawリテラルを使用することです。

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/...
チロ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コードに挿入するために使用できます。GCCC ++で複数行のインラインアセンブリコードを記述する方法は?

これで、リラックスして、C20XYで標準化されるのを待つだけです。

C ++が尋ねられた:C ++マルチライン文字列リテラル

Ubuntu 16.04、GCC 6.4.0、binutils 2.26.1でテスト済み。


0

別の方法は、改行を削除するためのツールを使用することです。任意のテキストエディターを使用して文字列を記述し、完了したら、ここにテキストを貼り付けて、xcodeに再度コピーします。


1
本当に長期的な解決策はありません。後でもう一度変更する必要がある場合はどうでしょうか。Getは面倒ですが、すでに述べた複数行の技術を使用して、ファイルで直接フォーマットする方が良いでしょう。
Schwarzie2478
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.