C ++ çok satırlı dize değişmez değeri


415

C ++, à la Perl'de çok satırlı düz metin, sabit değişmez değerler kullanmanın bir yolu var mı? Belki #includebir dosya ing ile bazı ayrıştırma hilesi ? Birini düşünemiyorum, ama oğlum, bu iyi olurdu. C ++ 0x olacağını biliyorum.


1
Genellikle dize değişmezlerini koda gömmek istemezsiniz. I18N ve L10N için, dize değişmezlerini çalışma zamanında yüklenen bir yapılandırma dosyasına koymak tercih edilir.
Martin York

45
Dize değişmezlerini koda yerleştirmenin sorun olmadığı yeterli durumlar vardır: dize bunu kullanıcıyı temsil etmek için kullanılmıyorsa; ie: SQL deyimleri, dosya adları, kayıt defteri anahtarı adları, yürütülecek komut satırları, ...
mmmmmmmm

2
@Martin: Ancak bilmek yine de faydalı olabilir. Örneğin karmaşık düzenli ifadeleri parçalamak için yaptım.
Boojum

Yanıtlar:


591

İyi sıralama. En kolayı, sadece bitişik dize değişmezlerinin derleyici tarafından birleştirildiği gerçeğini kullanmaktır:

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.";

Girintinin önemi yoktur, çünkü tırnak içinde değildir.

Katıştırılmış yeni satırdan kaçmaya özen gösterdiğiniz sürece bunu da yapabilirsiniz. Bunun yapılmaması, ilk cevabımın yaptığı gibi derlenmeyecek:

const char * text2 =
  "Öte yandan, ben çıldırdım \
ve kelimenin tam anlamıyla birkaç satıra izin ver, \
her satırın alıntılar ile uğraşmadan \
içeriği. Bu işe yarıyor, ancak girintilemezsiniz. ";

Yine, her satırın sonundaki ters eğik çizgilere dikkat edin, satır bitmeden hemen önce olmalılar, kaynaktaki yeni satırdan kaçıyorlar, böylece her şey yeni satır orada yokmuş gibi davranıyor. Ters eğik çizgi yaptığınız konumlarda dizede yeni satırlar almazsınız. Bu formla metni açıkça girintilemezsiniz çünkü girinti daha sonra dizenin bir parçası haline gelir ve rastgele boşluklarla karışır.


3
Geçmişte ilk seçeneğin uygulamaya uygun olabileceği söylendi, ancak henüz bu sözdizimini onurlandırmayan bir derleyici bulamadım.
Jason Mock

28
@Jason: mutlaka C89 öncesi derleyicilerin bir parçası değildi, ancak C89'da tanımlandı ve bu nedenle esasen her yerde destekleniyor.
Jonathan Leffler

4
Ayrıca, dize gerçekten c ++ 98'de birden çok satırda biçimlendirilmesini istiyorsanız, alıntı yapılan her dize parçasındaki sonlandırma boşluğu yerine \ n kullanın. C ++ 11 ham değişmezleri hala benim favorim.
emsr

3
@ unwind Kaynak satırının sonundaki satırsonu dizenin bir parçası değildir, sadece atlanmıştır. Dizenin bir parçası olarak bir yeni satır istiyorsanız, satırın sonunda \ n \ olmalıdır.
hyde

2
Microsoft Visual Studio'da kötü bir hata var. Satırların sonunda ters eğik çizgiler kullanırsanız, dizenin içindeki metni otomatik olarak girintili hale getirir.
palota

408

C ++ 11'de ham dize değişmezleri var. Python ve Perl ve Ruby gibi kabuklarda ve senaryo dillerinde buradaki metin gibi.

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";

Dizedeki tüm boşluklar ve girinti ve satırsonları korunur.

Bunlar ayrıca utf-8 | 16 | 32 veya wchar_t (normal öneklerle birlikte) olabilir.

Burada kaçış dizisi olan V0G0N'nin aslında gerekli olmadığını belirtmeliyim. Onun varlığı dizginin içine koymak) izin verir. Başka bir deyişle, ben koymak olabilir

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

(ekstra alıntılara dikkat edin) ve yukarıdaki dize yine de doğru olur. Aksi takdirde,

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

Tırnakların içindeki parenler hala gereklidir.


24
Bu gerçekten istediğim şey, tırnak, ters eğik çizgi-Ns, kaçar ve hala gerçek dizede yeni satırlar görünmesini önlemek için yeteneği. Bu, gömülü kod (ör. Gölgelendiriciler veya Lua) için kullanışlıdır. Ne yazık ki, henüz C ++ - 0x kullanmıyoruz. :-(
mlepage

2
Kendimi gömülü SQL ve Python komut dosyaları için bunu düşünüyordum. Belki gcc C ++ 98 modunda kaymasına izin verirse, ama ne yazık ki hayır uğruna umuyordum.
emsr

3
Daha çok clang ve gcc'ye alışkınım. Bu derleyicilerde C ++ 0x veya c ++ 11 için bir bayrak ayarlamanız gerekir. MS web sitesine baktığımda henüz ham değişmezleri yok gibi görünüyor. MS yeni derleyici güncelleştirmelerini C ++ özellikleri uygulandığı gibi daha hızlı yayınlayacak anlıyorum. En son kanayan kenar için Visual C ++ Derleyici Kasım 2012 CTP [ microsoft.com/en-us/download/details.aspx?id=35515] 'e bakın.
emsr

5
@rsethc Kod bloklarını yorumlamak için sadece #if 0… tuşunu kullanın #endif. Yuvalar da.
bobbogo

1
Vogon şiirinden esinlenildi!
Thane Plummer

27

#define MULTILINE(...) #__VA_ARGS__
Parantezler arasındaki her şeyi tüketir.
İstediğiniz sayıda ardışık boşluk karakteri tek bir boşlukla değiştirir.


1
Yeni \nsatırlara ihtiyacınız varsa ekleyebilirsiniz
Simon

O Not ` (and hence \ n ) is copied literally, but "` dönüştürülür \"Yani. MULTILINE(1, "2" \3)Verimleri "1, \"2\" \3".
Andreas Spindler

@AndreasSpindler Tırnaklar ve ters eğik çizgiler, bir dize veya karakter değişmez belirtecinin içinde göründükleri sürece (ek) ters eğik çizgilerden kaçarlar. Ne demek istediğinden emin değilim. Eşsiz bir alıntıya (çift veya tek) sahip olmak yasadışıdır, bu nedenle kasılmalar işe yaramaz ya da yine de tek bir sayıdır, ki bu muhtemelen en büyük dezavantajdır. Yine de +1. "Gerçek programcılar" her zaman araya giren yeni satır olmadan çiftler halinde kasılmalar kullanır, böylece tek tırnaklar dengede.
Potatoswatter

Mesele şu ki, "parantezler arasında her şeyi tüketir".
Andreas Spindler

25

Çok satırlı dizeler girmenin muhtemelen uygun bir yolu makroları kullanmaktır. Bu yalnızca tırnak işaretleri ve parantezler dengeliyse çalışır ve 'üst düzey' virgül içermez:

#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);

Gcc 4.6 veya g ++ 4.6 ile derlendiğinde, bu aşağıdakileri üretir: [[Using this trick(,) you don't need to use quotes. Though newlines and multiple white spaces will be replaced by a single whitespace.]]

Unutmayın ki ,Parantez veya tırnak içinde bulunmadıkça, dizenin içinde olamayacağını . Tek tırnak işaretleri mümkündür, ancak derleyici uyarıları oluşturur.

Düzenleme: Yorumlarda belirtildiği gibi #define MULTI_LINE_STRING(...) #__VA_ARGS__, kullanımını sağlar ,.


C ++ 'da bazı lua kod parçacıkları eklemek istediğim bir proje için, çok satırlı dizelere girdiğim küçük bir python betiği yazdım ve bunun bir c ++ kaynak dosyası oluşturmasına izin verdim.
bcmpinc

Benim için mükemmel, birim testi için bir kolajda dosyasından dev bir çok satırlı kayan liste dizesi ekleyerek. Her yere tırnak koymaktan hoşlanmadım, kopyala yapıştır çözümüne ihtiyacım vardı.
Soylent Graham

7
#define MULTILINE(...) #__VA_ARGS__Dizenizin virgül içermesini istiyorsanız kullanabilirsiniz .
Simon

2
Bu, bazı durumlar için kullanışlı ve diğerleri için ölümcül olan çoğu ekstra beyaz alanı (hepsi \nve dahil \r) çıkaracaktır .
BCS

17

Bunu da yapabilirsiniz:

const char *longString = R""""(
This is 
a very 
long 
string
)"""";

2
teşekkürler, bu harika, C.'de bile çalışıyor tabii ki, char longString[] = R""""( This is a very long string )""""; benim için de çalışıyor.
struggling_learner

2
Bu, dizeyi yeni bir satırla başlatır ve bitirir mi?
Tim MB

1
Bu bir var çiğ dize . C ++ 11'den beri kullanılabilir.
Mikolasan

15

Bunu sadece yapabilirsiniz:

const char *text = "This is my string it is "
     "very long";

@ Unwind'ın cevabından farkı nedir?
Sisir

1
@Sisir Gevşemeden 2 dakika önce yayınladım.
Eric

Bu kısmı kaçırdığım için özür dileriz. Benim +1
Sisir

10

Bir ons deneyim bir ton teoriye değer olduğundan, aşağıdakiler için küçük bir test programı denedim 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"
};

cpp -P -std=c++11 filenameÇoğaltmak için bu parçayı derleyin .

Hüner arkasında #__VA_ARGS__olduğunu __VA_ARGS__virgül ayırıcı işlemez. Böylece dizgi operatörüne iletebilirsiniz. Öndeki ve sondaki boşluklar kesilir ve sözcükler arasındaki boşluklar (satır satırları dahil) tek bir alana sıkıştırılır. Parantezlerin dengelenmesi gerekir. Bu eksikliklerin, C ++ 11 tasarımcılarının neden #__VA_ARGS__ham dize değişmezlerine ihtiyaç duyduklarını açıkladığını düşünüyorum.


9

Sadece @ emsr'in @ unwind'ın cevabındaki açıklamasını biraz açıklamak için, biri bir C ++ 11 derleyicisine (GCC 4.2.1 diyelim) sahip olmak için yeterince şanslı değilse ve yeni satırları dizeye gömmek istiyorsa (char * veya sınıf dizesi), böyle bir şey yazabilirsiniz:

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.";

Çok açık, doğru, ama @ emsr'in kısa yorumu bunu ilk kez okuduğumda bana atlamadı, bu yüzden bunu kendim keşfetmek zorunda kaldım. İnşallah birkaç dakika daha birini kurtardım.


-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";

Lütfen cevabınıza bir açıklama ekleyin ve sadece kod parçacıklarını değil
Geordie

-1

Seçenek 1. Destek kitaplığını kullanarak dizeyi aşağıdaki gibi bildirebilirsiniz

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);

Seçenek 2. Projenizde destek yoksa, modern C ++ 'da std :: string_view () kullanabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.