Czy jest jakiś sposób na posiadanie wieloliniowych tekstów stałych, literałów stałych w C ++, à la Perl? Może jakiś parsowanie sztuczki z #include
ingowaniem pliku? Nie mogę myśleć o jednym, ale chłopaku, byłoby miło. Wiem, że będzie w C ++ 0x.
Czy jest jakiś sposób na posiadanie wieloliniowych tekstów stałych, literałów stałych w C ++, à la Perl? Może jakiś parsowanie sztuczki z #include
ingowaniem pliku? Nie mogę myśleć o jednym, ale chłopaku, byłoby miło. Wiem, że będzie w C ++ 0x.
Odpowiedzi:
Cóż ... W pewnym sensie. Najłatwiej jest po prostu użyć faktu, że sąsiadujące literały łańcuchowe są łączone przez kompilator:
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.";
Wcięcie nie ma znaczenia, ponieważ nie ma go w cudzysłowie.
Możesz to również zrobić, o ile będziesz starał się uciec z wbudowanego nowego wiersza. Nieprzestrzeganie tego, podobnie jak moja pierwsza odpowiedź, nie spowoduje kompilacji:
const char * text2 = „Z drugiej strony zwariowałem \ i naprawdę pozwól, aby dosłowność obejmowała kilka linii, \ bez zawracania głowy cytowaniem każdego wiersza \ zadowolony. To działa, ale nie można wcięcia. ";
Ponownie zwróć uwagę na te ukośniki odwrotne na końcu każdej linii, muszą znajdować się bezpośrednio przed końcem linii, uciekają od nowej linii w źródle, aby wszystko działało tak, jakby nowej linii nie było. W miejscach, w których wystąpiły ukośniki odwrotne, nie pojawiają się znaki nowej linii. W tym formularzu nie można oczywiście wciąć tekstu, ponieważ wcięcie stałoby się częścią łańcucha, zmieniając go losowymi spacjami.
W C ++ 11 masz surowe literały łańcuchowe. Coś jak tekst tutaj w powłokach i językach skryptowych, takich jak Python, Perl i 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";
Wszystkie spacje i wcięcia oraz znaki nowej linii w łańcuchu są zachowane.
Mogą to być również utf-8 | 16 | 32 lub wchar_t (ze zwykłymi prefiksami).
Powinienem zaznaczyć, że sekwencja ucieczki, V0G0N, nie jest tutaj tak naprawdę potrzebna. Jego obecność pozwoliłaby na umieszczenie) w sznurku. Innymi słowy, mógłbym to zrobić
"(by Prostetnic Vogon Jeltz; see p. 56/57)"
(zwróć uwagę na dodatkowe cytaty), a ciąg powyżej nadal będzie poprawny. W przeciwnym razie równie dobrze mógłbym skorzystać
const char * vogon_poem = R"( ... )";
Pareny znajdujące się w cudzysłowie są nadal potrzebne.
#if 0
…, #endif
aby skomentować bloki kodu. Gniazda też.
#define MULTILINE(...) #__VA_ARGS__
Zużywa wszystko między nawiasami.
Zastępuje dowolną liczbę następujących po sobie białych znaków jednym spacją.
\n
jeśli potrzebujesz nowych linii
` (and hence
\ n ) is copied literally, but
"jest konwertowany na \"
. Więc MULTILINE(1, "2" \3)
daje "1, \"2\" \3"
.
Prawdopodobnie wygodnym sposobem wprowadzania ciągów wieloliniowych jest użycie makr. Działa to tylko wtedy, gdy cytaty i nawiasy są zrównoważone i nie zawiera przecinków „najwyższego poziomu”:
#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);
Skompilowany z gcc 4.6 lub g ++ 4.6, daje to: [[Using this trick(,) you don't need to use quotes. Though newlines and multiple white spaces will be replaced by a single whitespace.]]
Zauważ, że ,
nie może być w ciągu, chyba że jest zawarty w nawiasie lub cudzysłowie. Pojedyncze cudzysłowy są możliwe, ale tworzą ostrzeżenia kompilatora.
Edycja: Jak wspomniano w komentarzach, #define MULTI_LINE_STRING(...) #__VA_ARGS__
umożliwia użycie ,
.
#define MULTILINE(...) #__VA_ARGS__
jeśli chcesz, aby Twój ciąg zawierał przecinki.
\n
i \r
), co jest w niektórych przypadkach przydatne, a dla innych śmiertelne.
Możesz także to zrobić:
const char *longString = R""""(
This is
a very
long
string
)"""";
char longString[] = R""""( This is a very long string )"""";
też działa dla mnie.
Ponieważ uncja doświadczenia jest warta mnóstwa teorii, wypróbowałem mały program testowy dla 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"
};
Skompiluj ten fragment, cpp -P -std=c++11 filename
aby go odtworzyć.
Sztuczka #__VA_ARGS__
polega na tym, __VA_ARGS__
że nie przetwarza separatora przecinków. Możesz więc przekazać go operatorowi naciągania. Wiodące i końcowe spacje są przycinane, a spacje (w tym nowe linie) między słowami są następnie kompresowane do pojedynczej spacji. Nawiasy muszą być zrównoważone. Myślę, że te niedociągnięcia wyjaśniają, dlaczego projektanci C ++ 11 #__VA_ARGS__
dostrzegli potrzebę literałów surowych.
Aby wyjaśnić nieco komentarz @ emsr w odpowiedzi @ unwind, jeśli nie ma się szczęścia, aby mieć kompilator C ++ 11 (powiedzmy GCC 4.2.1), i chcemy osadzić znaki nowej linii w ciągu (albo char * lub ciąg klasy), można napisać coś takiego:
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.";
To bardzo oczywiste, prawda, ale krótki komentarz @ emsr nie wyskoczył na mnie, gdy przeczytałem to po raz pierwszy, więc musiałem to odkryć dla siebie. Mam nadzieję, że zaoszczędziłem komuś jeszcze kilka minut.
// 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";
Opcja 1. Korzystając z biblioteki boost, możesz zadeklarować ciąg znaków jak poniżej
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);
Opcja 2. Jeśli boost nie jest dostępny w twoim projekcie, możesz użyć std :: string_view () we współczesnym C ++.