มีวิธีใดบ้างที่จะมีข้อความธรรมดาหลายบรรทัดตัวอักษรคงที่ใน C ++ หรือไม่? อาจจะมีเคล็ดลับการแยกวิเคราะห์ด้วย#include
ไฟล์หรือไม่ ฉันคิดไม่ออกเลย แต่เด็กผู้ชายนั่นคงจะดี ฉันรู้ว่ามันจะอยู่ใน C ++ 0x
มีวิธีใดบ้างที่จะมีข้อความธรรมดาหลายบรรทัดตัวอักษรคงที่ใน C ++ หรือไม่? อาจจะมีเคล็ดลับการแยกวิเคราะห์ด้วย#include
ไฟล์หรือไม่ ฉันคิดไม่ออกเลย แต่เด็กผู้ชายนั่นคงจะดี ฉันรู้ว่ามันจะอยู่ใน C ++ 0x
คำตอบ:
ดี ... ประเภทของ วิธีที่ง่ายที่สุดคือการใช้ข้อเท็จจริงที่ว่าสตริงตัวอักษรที่อยู่ติดกันนั้นต่อกันโดยคอมไพเลอร์:
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.";
การเยื้องไม่สำคัญเนื่องจากไม่อยู่ในเครื่องหมายคำพูด
คุณยังสามารถทำสิ่งนี้ได้ตราบใดที่คุณยังสามารถหลบเลี่ยงการขึ้นบรรทัดใหม่ได้ การไม่ทำเช่นนั้นเหมือนคำตอบแรกที่ฉันทำจะไม่รวบรวม:
const char * text2 = "ที่นี่ตรงกันข้ามฉันบ้าไปแล้ว \ และปล่อยให้ตัวอักษรขยายหลายบรรทัดจริงๆ \ โดยไม่ต้องรบกวนด้วยการอ้างอิงแต่ละบรรทัด \ เนื้อหา. ใช้งานได้ แต่คุณไม่สามารถเยื้องได้ ";
อีกครั้งให้สังเกตว่าแบ็กสแลชเหล่านั้นที่จุดสิ้นสุดของแต่ละบรรทัดต้องอยู่ในทันทีก่อนที่บรรทัดจะสิ้นสุดพวกเขากำลังหลบหนีขึ้นบรรทัดใหม่ในแหล่งที่มา คุณไม่ได้รับการขึ้นบรรทัดใหม่ในสตริงที่ตำแหน่งที่คุณมีแบ็กสแลช ด้วยแบบฟอร์มนี้คุณจะไม่สามารถเยื้องข้อความได้อย่างชัดเจนเนื่องจากการเยื้องจะกลายเป็นส่วนหนึ่งของสตริงทำให้อ่านด้วยช่องว่างแบบสุ่ม
ใน C ++ 11 คุณมีตัวอักษรสตริงดิบ เรียงจากข้อความที่นี่ในเชลล์และภาษาสคริปต์เช่น Python และ Perl และ 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";
ช่องว่างและการเยื้องและบรรทัดใหม่ทั้งหมดในสตริงจะถูกเก็บรักษาไว้
สิ่งเหล่านี้สามารถเป็น utf-8 | 16 | 32 หรือ wchar_t (พร้อมคำนำหน้าตามปกติ)
ฉันควรชี้ให้เห็นว่าลำดับ escape, V0G0N ไม่จำเป็นจริงๆที่นี่ การมีอยู่ของมันจะช่วยให้ใส่ "ในสตริงได้หรืออาจกล่าวได้ว่าฉันทำได้
"(by Prostetnic Vogon Jeltz; see p. 56/57)"
(หมายเหตุเครื่องหมายพิเศษ) และสตริงด้านบนจะยังคงถูกต้อง ไม่อย่างนั้นฉันก็สามารถใช้เช่นกัน
const char * vogon_poem = R"( ... )";
parens ที่อยู่ในเครื่องหมายคำพูดยังคงต้องการ
#if 0
... #endif
เพื่อคอมเม้นต์บล็อคของโค้ด รังเกินไป
#define MULTILINE(...) #__VA_ARGS__
กินทุกอย่างระหว่างวงเล็บ
แทนที่อักขระช่องว่างต่อเนื่องจำนวนเท่าใดก็ได้ด้วยช่องว่างเดียว
\n
หากคุณต้องการขึ้นบรรทัดใหม่
` (and hence
\ n ) is copied literally, but
"` จะถูกแปลงเป็น\"
ดังนั้น. MULTILINE(1, "2" \3)
อัตราผลตอบแทน"1, \"2\" \3"
.
วิธีที่สะดวกสบายในการป้อนสตริงหลายบรรทัดคือการใช้มาโคร ใช้งานได้ก็ต่อเมื่อคำพูดและวงเล็บมีความสมดุลและไม่มีเครื่องหมายจุลภาค 'ระดับสูงสุด':
#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 หรือ g ++ 4.6 สิ่งนี้ก่อให้เกิด: [[Using this trick(,) you don't need to use quotes. Though newlines and multiple white spaces will be replaced by a single whitespace.]]
โปรดทราบว่า,
ไม่สามารถอยู่ในสตริงได้เว้นแต่จะอยู่ในวงเล็บหรือเครื่องหมายคำพูด คำพูดเดียวเป็นไปได้ แต่สร้างคำเตือนคอมไพเลอร์
แก้ไข:ตามที่ระบุไว้ในความคิดเห็นที่ช่วยให้การใช้งานของ#define MULTI_LINE_STRING(...) #__VA_ARGS__
,
#define MULTILINE(...) #__VA_ARGS__
ถ้าคุณต้องการให้สตริงของคุณมีเครื่องหมายจุลภาค
\n
และ\r
) ซึ่งเป็นประโยชน์สำหรับบางกรณีและเป็นอันตรายถึงชีวิตสำหรับผู้อื่น
คุณยังสามารถทำสิ่งนี้:
const char *longString = R""""(
This is
a very
long
string
)"""";
char longString[] = R""""( This is a very long string )"""";
เช่นกันสำหรับฉัน
เนื่องจากประสบการณ์หนึ่งออนซ์มีค่ามากกว่าทฤษฎีฉันจึงลองโปรแกรมทดสอบเล็ก ๆ สำหรับ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
เพื่อทำซ้ำ
เคล็ดลับที่อยู่เบื้องหลัง#__VA_ARGS__
นั้น__VA_ARGS__
ไม่ได้ดำเนินการคั่นด้วยเครื่องหมายจุลภาค ดังนั้นคุณสามารถส่งต่อไปยังผู้ประกอบการ stringizing ช่องว่างนำหน้าและต่อท้ายถูกตัดแต่งและช่องว่าง (รวมถึงบรรทัดใหม่) ระหว่างคำถูกบีบอัดเป็นช่องว่างเดียวแล้ว วงเล็บต้องมีความสมดุล ฉันคิดว่าข้อบกพร่องเหล่านี้อธิบายว่าทำไมนักออกแบบของ C ++ 11 ถึงจะ#__VA_ARGS__
เห็นความต้องการตัวอักษรสตริงดิบ
เพียงแค่ให้ความเห็นเล็กน้อยเกี่ยวกับความคิดเห็นของ @ emsr ในคำตอบของ @ relax หากไม่มีโชคดีพอที่จะมีคอมไพเลอร์ C ++ 11 (พูด GCC 4.2.1) และหนึ่งต้องการฝังบรรทัดใหม่ในสตริง (ทั้งอักขระ * หรือคลาสสตริง) สามารถเขียนดังนี้:
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.";
ชัดเจนมากจริง แต่ความเห็นสั้น ๆ ของ @ emsr ไม่ได้กระโดดลงมาที่ฉันเมื่อฉันอ่านครั้งแรกดังนั้นฉันจึงต้องค้นหาสิ่งนี้ด้วยตัวเอง หวังว่าฉันจะช่วยคนอื่นซักครู่
// 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";
ตัวเลือกที่ 1 ใช้ห้องสมุดเพิ่มคุณสามารถประกาศสตริงดังต่อไปนี้
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);
ตัวเลือกที่ 2 ถ้าไม่มีบูสต์ในโครงการของคุณคุณสามารถใช้ std :: string_view () ใน c ++ ที่ทันสมัย