สตริง c ++ หลายบรรทัดตามตัวอักษร


415

มีวิธีใดบ้างที่จะมีข้อความธรรมดาหลายบรรทัดตัวอักษรคงที่ใน C ++ หรือไม่? อาจจะมีเคล็ดลับการแยกวิเคราะห์ด้วย#includeไฟล์หรือไม่ ฉันคิดไม่ออกเลย แต่เด็กผู้ชายนั่นคงจะดี ฉันรู้ว่ามันจะอยู่ใน C ++ 0x


1
โดยทั่วไปคุณไม่ต้องการฝังตัวอักษรสตริงลงในรหัส สำหรับ I18N และ L10N จะดีกว่าที่จะใส่ตัวอักษรสตริงลงในไฟล์การกำหนดค่าที่โหลดในเวลาทำงาน
Martin York

45
มีหลายกรณีที่การใส่ตัวอักษรสตริงลงในโค้ดไม่ใช่ปัญหา: หากสตริงไม่ได้ถูกใช้เพื่อแสดงถึงผู้ใช้ เช่น: คำสั่ง SQL ชื่อไฟล์ชื่อรีจิสทรีคีย์บรรทัดคำสั่งที่จะดำเนินการ ...
mmmmmmmm

2
@ มาร์ติน: มันยังมีประโยชน์ที่จะรู้อย่างไรก็ตาม ฉันได้ทำมันเพื่อสลาย regexs ที่ซับซ้อนเช่น
Boojum

คำตอบ:


591

ดี ... ประเภทของ วิธีที่ง่ายที่สุดคือการใช้ข้อเท็จจริงที่ว่าสตริงตัวอักษรที่อยู่ติดกันนั้นต่อกันโดยคอมไพเลอร์:

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 =
  "ที่นี่ตรงกันข้ามฉันบ้าไปแล้ว \
และปล่อยให้ตัวอักษรขยายหลายบรรทัดจริงๆ \
โดยไม่ต้องรบกวนด้วยการอ้างอิงแต่ละบรรทัด \
เนื้อหา. ใช้งานได้ แต่คุณไม่สามารถเยื้องได้ ";

อีกครั้งให้สังเกตว่าแบ็กสแลชเหล่านั้นที่จุดสิ้นสุดของแต่ละบรรทัดต้องอยู่ในทันทีก่อนที่บรรทัดจะสิ้นสุดพวกเขากำลังหลบหนีขึ้นบรรทัดใหม่ในแหล่งที่มา คุณไม่ได้รับการขึ้นบรรทัดใหม่ในสตริงที่ตำแหน่งที่คุณมีแบ็กสแลช ด้วยแบบฟอร์มนี้คุณจะไม่สามารถเยื้องข้อความได้อย่างชัดเจนเนื่องจากการเยื้องจะกลายเป็นส่วนหนึ่งของสตริงทำให้อ่านด้วยช่องว่างแบบสุ่ม


3
ฉันได้รับการบอกในอดีตว่าตัวเลือกแรกสามารถนำไปใช้ได้จริง แต่ฉันยังหาคอมไพเลอร์ที่ไม่ให้เกียรติไวยากรณ์นั้น
Jason Mock

28
@ Jason: มันไม่จำเป็นต้องเป็นส่วนหนึ่งของคอมไพเลอร์ pre-C89 แต่มันถูกกำหนดใน C89 และดังนั้นจึงรองรับทุกที่เป็นหลัก
Jonathan Leffler

4
นอกจากนี้หากคุณต้องการจัดรูปแบบสตริงในหลายบรรทัดใน c ++ 98 ให้แทนที่ \ n สำหรับพื้นที่ยุติในแต่ละส่วนของสตริงที่ยกมา C ++ 11 ตัวอักษรดิบยังคงเป็นที่ชื่นชอบ
emsr

3
@unwind โปรดทราบว่าการขึ้นบรรทัดใหม่ที่ท้ายบรรทัดซอร์สไม่ได้เป็นส่วนหนึ่งของสตริงมันเพิ่งถูกข้ามไป หากคุณต้องการขึ้นบรรทัดใหม่เป็นส่วนหนึ่งของสตริงคุณต้องมี \ n \ ที่ส่วนท้ายของบรรทัด
hyde

2
มีข้อผิดพลาดที่น่ารังเกียจใน Microsoft Visual Studio หากคุณใช้แบ็กสแลชที่ท้ายบรรทัดข้อความนั้นจะเยื้องข้อความภายในสตริงโดยอัตโนมัติ
palota

408

ใน 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 ที่อยู่ในเครื่องหมายคำพูดยังคงต้องการ


24
นี่คือสิ่งที่ฉันต้องการจริงๆความสามารถในการหลีกเลี่ยงคำพูดเครื่องหมายแบ็กสแลช - เอ็นหนีออกมาและยังมีการขึ้นบรรทัดใหม่ในสตริงจริง สิ่งนี้มีประโยชน์สำหรับโค้ดแบบฝัง (เช่น shaders หรือ Lua) น่าเสียดายที่เรายังไม่ได้ใช้ C ++ - 0x :-(
mlepage

2
ฉันกำลังพิจารณาเรื่องนี้เพื่อฝังสคริปต์ SQL และ Python ด้วยตนเอง ฉันหวังเพื่อประโยชน์ของคุณถ้าบางที gcc จะปล่อยให้มันเลื่อนผ่านในโหมด C ++ 98 แต่อนิจจาไม่
emsr

3
ฉันคุ้นเคยกับการคลุกคลีและ gcc มากขึ้น ในคอมไพเลอร์นี้คุณต้องตั้งค่าสถานะสำหรับ C ++ 0x หรือ c ++ 11 เว็บไซต์ Lookin na MS ดูเหมือนว่าพวกเขายังไม่มีตัวอักษรดิบ ฉันเข้าใจว่า MS จะปล่อยการปรับปรุงคอมไพเลอร์ใหม่เร็วขึ้นเมื่อมีการใช้คุณสมบัติ C ++ มองหาคอมไพเลอร์ Visual C ++ พฤศจิกายน 2012 CTP [ microsoft.com/en-us/download/details.aspx?id=35515]เพื่อหาขอบเลือดออกล่าสุด
emsr

5
@rsethc เพียงใช้#if 0... #endifเพื่อคอมเม้นต์บล็อคของโค้ด รังเกินไป
bobbogo

1
แรงบันดาลใจจากบทกวี Vogon!
Thane Plummer

27

#define MULTILINE(...) #__VA_ARGS__
กินทุกอย่างระหว่างวงเล็บ
แทนที่อักขระช่องว่างต่อเนื่องจำนวนเท่าใดก็ได้ด้วยช่องว่างเดียว


1
คุณสามารถเพิ่ม\nหากคุณต้องการขึ้นบรรทัดใหม่
Simon

โปรดทราบว่า` (and hence \ n ) is copied literally, but "` จะถูกแปลงเป็น\"ดังนั้น. MULTILINE(1, "2" \3)อัตราผลตอบแทน"1, \"2\" \3".
แอนเดรี Spindler

@AndreasSpindler เครื่องหมายคำพูดและแบ็กสแลชที่เหมือนกันจะถูกหลบหนีโดยแบ็กสแลช (เพิ่มเติม) ตราบใดที่ปรากฏในสตริงหรือโทเค็นตัวอักษร ไม่แน่ใจว่าประเด็นของคุณคืออะไร เป็นสิ่งผิดกฎหมายที่จะมีการเสนอราคาที่ไม่ตรงกัน (สองครั้งหรือเดี่ยว) ดังนั้นการหดตัวไม่ทำงานหรือเป็นจำนวนคี่ของพวกเขาต่อไปซึ่งอาจเป็นข้อเสียที่ใหญ่ที่สุด +1 อยู่ดี "โปรแกรมเมอร์จริง" มักจะใช้การหดตัวเป็นคู่โดยไม่มีการขึ้นบรรทัดใหม่ดังนั้นการเสนอราคาแบบเดียว
Potatoswatter

ประเด็นก็คือเขาเขียนว่า "สิ้นเปลืองทุกอย่างระหว่างวงเล็บ"
Andreas Spindler

25

วิธีที่สะดวกสบายในการป้อนสตริงหลายบรรทัดคือการใช้มาโคร ใช้งานได้ก็ต่อเมื่อคำพูดและวงเล็บมีความสมดุลและไม่มีเครื่องหมายจุลภาค 'ระดับสูงสุด':

#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__,


สำหรับโครงการที่ฉันต้องการรวมตัวอย่างโค้ด lua ใน c ++ ฉันสิ้นสุดการเขียนสคริปต์ python ขนาดเล็กซึ่งฉันป้อนสตริงหลายบรรทัดและอนุญาตให้สร้างไฟล์ต้นฉบับ c ++
bcmpinc

สมบูรณ์แบบสำหรับฉันเพิ่มสตริงรายชื่อลอยหลายบรรทัดขนาดใหญ่จากไฟล์ collada สำหรับการทดสอบหน่วย ฉันไม่ได้คิดที่จะใส่เครื่องหมายคำพูดทุกที่ฉันต้องการโซลูชันคัดลอกและวาง
Soylent Graham

7
คุณสามารถใช้#define MULTILINE(...) #__VA_ARGS__ถ้าคุณต้องการให้สตริงของคุณมีเครื่องหมายจุลภาค
Simon

2
โปรดทราบว่าวิธีนี้จะช่วยให้ whitesapce ส่วนใหญ่พิเศษ (รวมถึงทั้งหมด\nและ\r) ซึ่งเป็นประโยชน์สำหรับบางกรณีและเป็นอันตรายถึงชีวิตสำหรับผู้อื่น
BCS

17

คุณยังสามารถทำสิ่งนี้:

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

2
ขอบคุณนี่เป็นสิ่งที่ยอดเยี่ยมใช้งานได้ดีแม้ใน C. อย่างชัดเจนchar longString[] = R""""( This is a very long string )""""; เช่นกันสำหรับฉัน
ดิ้นรน

2
สิ่งนี้เริ่มต้นและจบด้วยสตริงขึ้นบรรทัดใหม่หรือไม่?
ทิม MB

1
มันเป็นตัวอักษรสตริงดิบ มีให้ตั้งแต่ C ++ 11
Mikolasan

15

คุณสามารถทำสิ่งนี้:

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

มันแตกต่างจากคำตอบของ @ relax อย่างไร?
Sisir

1
@Sisir ฉันโพสต์ไว้ 2 นาทีก่อนที่จะผ่อนคลาย
Eric

ขอโทษที่หายไปส่วนหนึ่ง +1 ของฉัน
Sisir

10

เนื่องจากประสบการณ์หนึ่งออนซ์มีค่ามากกว่าทฤษฎีฉันจึงลองโปรแกรมทดสอบเล็ก ๆ สำหรับ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__เห็นความต้องการตัวอักษรสตริงดิบ


9

เพียงแค่ให้ความเห็นเล็กน้อยเกี่ยวกับความคิดเห็นของ @ 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 ไม่ได้กระโดดลงมาที่ฉันเมื่อฉันอ่านครั้งแรกดังนั้นฉันจึงต้องค้นหาสิ่งนี้ด้วยตัวเอง หวังว่าฉันจะช่วยคนอื่นซักครู่


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

โปรดเพิ่มคำอธิบายให้กับคำตอบของคุณและไม่ใช่แค่ตัวอย่างโค้ด
Geordie

-1

ตัวเลือกที่ 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 ++ ที่ทันสมัย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.