C ++ string multiline literal

415

Apakah ada cara untuk memiliki multi-line plain-text, literal konstan dalam C ++, à la Perl? Mungkin beberapa trik parsing dengan #includefile? Saya tidak bisa memikirkan satu, tapi nak, itu akan menyenangkan. Saya tahu ini akan berada di C ++ 0x.

rbbond
sumber
1
Secara umum Anda tidak ingin menanamkan string literal ke dalam kode. Untuk I18N dan L10N lebih baik menempatkan string literal ke dalam file konfigurasi yang dimuat pada saat dijalankan.
Martin York
45
Ada cukup kasus di mana menempatkan string literal ke dalam kode tidak menjadi masalah: jika string tidak digunakan untuk mewakilinya kepada pengguna; yaitu: pernyataan SQL, nama file, nama-nama kunci registri, baris perintah yang akan dieksekusi, ...
mmmmmmmm
2
@ Martin: Masih bisa berguna untuk tahu. Saya sudah melakukannya untuk memecah regex kompleks, misalnya.
Boojum

Jawaban:

591

Baiklah ... Semacam. Cara termudah adalah dengan menggunakan fakta bahwa literal string yang berdekatan disatukan oleh kompiler:

const char *text =
  "This text is pretty long, but will be "
  "concatenated into just a single string. "
  "The disadvantage is that you have to quote "
  "each part, and newlines must be literal as "
  "usual.";

Lekukan itu tidak masalah, karena tidak ada di dalam tanda kutip.

Anda juga dapat melakukan ini, selama Anda berhati-hati untuk menghindari baris baru yang disematkan. Gagal melakukannya, seperti jawaban pertama saya, tidak akan mengkompilasi:

const char * text2 =
  "Di sini, di sisi lain, aku sudah gila \
dan benar-benar membiarkan span span literal beberapa,
tanpa repot-repot mengutip setiap baris \
kandungan. Ini berfungsi, tetapi Anda tidak dapat membuat indentasi. ";

Sekali lagi, perhatikan garis miring terbalik pada akhir setiap baris, mereka harus segera sebelum garis berakhir, mereka melarikan diri dari baris baru di sumber, sehingga semuanya bertindak seolah-olah baris baru tidak ada di sana. Anda tidak mendapatkan baris baru di string di lokasi tempat Anda mengalami garis miring terbalik. Dengan formulir ini, Anda jelas tidak dapat membuat indentasi teks karena indentasi kemudian akan menjadi bagian dari string, mengacaukannya dengan spasi acak.

beristirahat
sumber
3
Saya telah diberitahu di masa lalu bahwa opsi pertama bisa sampai implementasi, namun saya belum menemukan kompiler yang tidak menghormati sintaks itu.
Jason Mock
28
@Jason: itu belum tentu merupakan bagian dari kompiler pra-C89, tetapi didefinisikan dalam C89 dan karenanya pada dasarnya didukung di mana-mana.
Jonathan Leffler
4
Juga, jika Anda benar-benar ingin string yang diformat pada beberapa baris dalam c ++ 98 cukup gantikan \ n untuk ruang terminasi pada setiap fragmen string yang dikutip. C ++ 11 liter mentah masih menjadi favorit saya.
emsr
3
@unwind Perhatikan bahwa baris baru di akhir baris sumber tidak dibuat sebagai bagian dari string, hanya dilewati. Jika Anda ingin baris baru sebagai bagian dari string, Anda harus memiliki \ n \ di akhir baris.
hyde
2
Ada bug jahat di Microsoft Visual Studio. Jika Anda menggunakan garis miring terbalik di akhir baris, maka secara otomatis indentasi teks di dalam string.
palota
408

Di C ++ 11 Anda memiliki literal string mentah. Semacam seperti di sini-teks dalam shell dan bahasa skrip seperti Python dan Perl dan Ruby.

const char * vogon_poem = R"V0G0N(
             O freddled gruntbuggly thy micturations are to me
                 As plured gabbleblochits on a lurgid bee.
              Groop, I implore thee my foonting turlingdromes.   
           And hooptiously drangle me with crinkly bindlewurdles,
Or I will rend thee in the gobberwarts with my blurlecruncheon, see if I don't.

                (by Prostetnic Vogon Jeltz; see p. 56/57)
)V0G0N";

Semua spasi dan lekukan dan baris baru dalam string dipertahankan.

Ini juga bisa utf-8 | 16 | 32 atau wchar_t (dengan awalan biasa).

Saya harus menunjukkan bahwa urutan pelarian, V0G0N, sebenarnya tidak diperlukan di sini. Kehadirannya akan memungkinkan menempatkan) "di dalam string. Dengan kata lain, saya bisa meletakkan

                "(by Prostetnic Vogon Jeltz; see p. 56/57)"

(perhatikan kutipan tambahan) dan string di atas akan tetap benar. Kalau tidak, aku bisa saja menggunakannya

const char * vogon_poem = R"( ... )";

Parens di dalam tanda kutip masih diperlukan.

emsr
sumber
24
Ini benar-benar yang saya inginkan, kemampuan untuk menghindari tanda kutip, backslash-Ns, lolos, dan masih memiliki baris baru muncul di string yang sebenarnya. Ini berguna untuk kode yang disematkan (mis. Shader atau Lua). Sayangnya, kita belum menggunakan C ++ - 0x. :-(
mlepage
2
Saya sedang mempertimbangkan ini untuk skrip SQL dan Python tertanam sendiri. Saya berharap demi Anda jika mungkin gcc akan membiarkannya meluncur dalam mode C ++ 98 tetapi, sayangnya, tidak.
emsr
3
Saya lebih terbiasa berdentang dan gcc. Dalam kompiler ini, Anda harus menetapkan flag untuk C ++ 0x atau c ++ 11. Lihat situs web MS, sepertinya mereka belum memiliki literal mentah. saya mengerti bahwa MS akan merilis pembaruan kompiler baru lebih cepat ketika fitur C ++ diimplementasikan. Cari Visual C ++ Compiler November 2012 CTP [ microsoft.com/en-us/download/details.aspx?id=35515] untuk tepi pendarahan terbaru.
emsr
5
@ rsethc Cukup gunakan #if 0... #endifuntuk mengomentari blok kode. Sarang juga.
bobbogo
1
Terinspirasi oleh puisi Vogon!
Thane Plummer
27

#define MULTILINE(...) #__VA_ARGS__
Membutuhkan segalanya di antara tanda kurung.
Mengganti sejumlah karakter spasi putih berurutan dengan satu spasi.

Zlatan Stanojević
sumber
1
Anda dapat menambahkan \njika Anda memerlukan baris baru
Simon
Perhatikan bahwa ` (and hence \ n ) is copied literally, but "` diubah menjadi \". Jadi MULTILINE(1, "2" \3)hasilkan "1, \"2\" \3".
Andreas Spindler
@AndreasSpindler Kutipan dan backslash sama-sama lolos oleh backslash (tambahan) selama mereka muncul di dalam token string atau karakter literal. Tidak yakin apa maksud Anda. Adalah ilegal untuk memiliki penawaran yang tidak tertandingi (ganda atau tunggal), sehingga kontraksi tidak berfungsi, atau jumlah ganjil dari mereka, yang mungkin merupakan downside terbesar. Tetap memberi +1. "Programer sungguhan" selalu menggunakan kontraksi berpasangan tanpa baris baru yang mengganggu sehingga tanda kutip tunggal menyeimbangkan.
Potatoswatter
Intinya adalah bahwa ia menulis "menghabiskan segalanya di antara tanda kurung".
Andreas Spindler
25

Cara yang mungkin mudah untuk memasukkan string multi-line adalah dengan menggunakan makro. Ini hanya berfungsi jika tanda kutip dan tanda kurung seimbang dan tidak mengandung koma 'tingkat atas':

#define MULTI_LINE_STRING(a) #a
const char *text = MULTI_LINE_STRING(
  Using this trick(,) you don't need to use quotes.
  Though newlines and     multiple     white   spaces
  will be replaced by a single whitespace.
);
printf("[[%s]]\n",text);

Dikompilasi dengan gcc 4.6 atau g ++ 4.6, ini menghasilkan: [[Using this trick(,) you don't need to use quotes. Though newlines and multiple white spaces will be replaced by a single whitespace.]]

Perhatikan bahwa ,tidak bisa di dalam string, kecuali itu terkandung dalam tanda kurung atau kutipan. Kutipan tunggal dimungkinkan, tetapi membuat peringatan kompiler.

Sunting: Seperti yang disebutkan dalam komentar, #define MULTI_LINE_STRING(...) #__VA_ARGS__memungkinkan penggunaan ,.

bcmpinc
sumber
Untuk proyek di mana saya ingin memasukkan beberapa potongan kode lua di c ++, saya akhirnya menulis skrip python kecil, di mana saya memasukkan string multiline, dan membiarkannya menghasilkan file sumber c ++.
bcmpinc
Sempurna untuk saya, menambahkan multi-line float-list string dari file collada untuk pengujian unit. Saya tidak suka meletakkan tanda kutip di mana-mana, saya membutuhkan solusi salin & tempel.
Soylent Graham
7
Anda dapat menggunakan #define MULTILINE(...) #__VA_ARGS__jika Anda ingin string Anda mengandung koma.
Simon
2
Perhatikan bahwa ini akan menghapus sebagian besar whitesapce tambahan (termasuk semua \ndan \r), yang berguna untuk beberapa kasus dan berakibat fatal bagi yang lain.
BCS
17

Anda juga dapat melakukan ini:

const char *longString = R""""(
This is 
a very 
long 
string
)"""";
Raydelto Hernandez
sumber
2
terima kasih, ini hebat, bekerja bahkan dalam C. jelas, char longString[] = R""""( This is a very long string )""""; bekerja juga, untuk saya.
Berjuang_learner
2
Apakah ini memulai dan mengakhiri string dengan baris baru?
Tim MB
1
Ini adalah string string literal . Tersedia sejak C ++ 11.
Mikolasan
15

Anda bisa melakukan ini:

const char *text = "This is my string it is "
     "very long";
Eric
sumber
Apa bedanya dengan jawaban @rantai?
Sisir
1
@Sisir Saya mempostingnya 2 menit sebelum bersantai.
Eric
Permintaan maaf karena melewatkan bagian itu. +1 saya
Sisir
10

Karena satu ons pengalaman bernilai satu ton teori, saya mencoba program uji kecil untuk MULTILINE:

#define MULTILINE(...) #__VA_ARGS__

const char *mstr[] =
{
    MULTILINE(1, 2, 3),       // "1, 2, 3"
    MULTILINE(1,2,3),         // "1,2,3"
    MULTILINE(1 , 2 , 3),     // "1 , 2 , 3"
    MULTILINE( 1 , 2 , 3 ),   // "1 , 2 , 3"
    MULTILINE((1,  2,  3)),   // "(1,  2,  3)"
    MULTILINE(1
              2
              3),             // "1 2 3"
    MULTILINE(1\n2\n3\n),     // "1\n2\n3\n"
    MULTILINE(1\n
              2\n
              3\n),           // "1\n 2\n 3\n"
    MULTILINE(1, "2" \3)      // "1, \"2\" \3"
};

Kompilasi fragmen ini dengan cpp -P -std=c++11 filenameuntuk mereproduksi.

Trik di belakang #__VA_ARGS__adalah bahwa __VA_ARGS__tidak memproses pemisah koma. Jadi, Anda bisa meneruskannya ke operator merangkai. Leading dan trailing spasi dipangkas, dan spasi (termasuk baris baru) antara kata dikompresi menjadi satu spasi. Kurung harus seimbang. Saya pikir kekurangan ini menjelaskan mengapa para perancang C ++ 11, meskipun #__VA_ARGS__, melihat perlunya literal string mentah.

Andreas Spindler
sumber
9

Hanya untuk menjelaskan sedikit tentang komentar @ emsr dalam jawaban @elaksasi, jika seseorang tidak cukup beruntung untuk memiliki kompiler C ++ 11 (katakanlah GCC 4.2.1), dan seseorang ingin menyematkan baris baru dalam string (baik karakter * atau string kelas), seseorang dapat menulis sesuatu seperti ini:

const char *text =
  "This text is pretty long, but will be\n"
  "concatenated into just a single string.\n"
  "The disadvantage is that you have to quote\n"
  "each part, and newlines must be literal as\n"
  "usual.";

Sangat jelas, benar, tetapi komentar pendek @ emsr tidak langsung muncul ketika saya membaca ini pertama kali, jadi saya harus menemukan ini untuk diri saya sendiri. Mudah-mudahan, saya telah menyelamatkan orang lain beberapa menit.

CXJ
sumber
-1
// C++11. 
std::string index_html=R"html(
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>VIPSDK MONITOR</title>
    <meta http-equiv="refresh" content="10">
</head>
<style type="text/css">
</style>
</html>
)html";
pengguna3635122
sumber
Harap tambahkan penjelasan untuk jawaban Anda dan bukan hanya cuplikan kode
Geordie
-1

Opsi 1. Menggunakan boost library, Anda dapat mendeklarasikan string seperti di bawah ini

const boost::string_view helpText = "This is very long help text.\n"
      "Also more text is here\n"
      "And here\n"

// Pass help text here
setHelpText(helpText);

Opsi 2. Jika boost tidak tersedia di proyek Anda, Anda dapat menggunakan std :: string_view () di C ++ modern.

piyu2cool
sumber