C ++ chuỗi đa nghĩa


415

Có cách nào để có văn bản đơn giản nhiều dòng, chữ không đổi trong C ++, à la Perl không? Có thể một số thủ thuật phân tích cú pháp với #includeing một tập tin? Tôi không thể nghĩ về một, nhưng chàng trai, điều đó sẽ tốt đẹp. Tôi biết nó sẽ ở C ++ 0x.


1
Nói chung, bạn không muốn nhúng chuỗi ký tự vào mã. Đối với I18N và L10N, tốt hơn là đặt chuỗi ký tự chuỗi vào tệp cấu hình được tải khi chạy.
Martin York

45
Có đủ các trường hợp trong đó việc đưa chuỗi ký tự vào mã không phải là vấn đề: nếu chuỗi không được sử dụng để đại diện cho người dùng; tức là: các câu lệnh SQL, tên tệp, tên khóa đăng ký, các dòng lệnh sẽ được thực thi, ...
mmmmmmmm

2
@Martin: Tuy nhiên, vẫn có thể hữu ích để biết. Tôi đã làm điều đó để phá vỡ các regex phức tạp, ví dụ.
Boojum

Câu trả lời:


591

Chà ... Sắp xếp Đơn giản nhất là chỉ sử dụng thực tế là các chuỗi ký tự liền kề được nối bởi trình biên dịch:

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

Việc thụt lề không thành vấn đề, vì nó không nằm trong dấu ngoặc kép.

Bạn cũng có thể làm điều này, miễn là bạn cẩn thận để thoát khỏi dòng mới được nhúng. Không làm như vậy, như câu trả lời đầu tiên của tôi đã làm, sẽ không biên dịch:

const char * text2 =
  "Ở đây, mặt khác, tôi đã phát điên \
và thực sự để cho dòng chữ trải dài vài dòng, \
mà không bận tâm đến việc trích dẫn từng dòng \
Nội dung. Điều này hoạt động, nhưng bạn không thể thụt lề. ";

Một lần nữa, lưu ý các dấu gạch chéo ngược ở cuối mỗi dòng, chúng phải ở ngay trước khi dòng kết thúc, chúng đang thoát dòng mới trong nguồn, để mọi thứ hoạt động như thể dòng mới ở đó. Bạn không nhận được dòng mới trong chuỗi tại các vị trí mà bạn có dấu gạch chéo ngược. Với hình thức này, rõ ràng bạn không thể thụt lề văn bản vì việc thụt lề sau đó sẽ trở thành một phần của chuỗi, cắt xén nó với các khoảng trắng ngẫu nhiên.


3
Trước đây tôi đã nói rằng tùy chọn đầu tiên có thể được triển khai, tuy nhiên tôi vẫn chưa tìm thấy trình biên dịch không tôn trọng cú pháp đó.
Jason Mock

28
@Jason: nó không nhất thiết là một phần của trình biên dịch trước C89, nhưng nó được định nghĩa trong C89 và do đó về cơ bản được hỗ trợ ở mọi nơi.
Jonathan Leffler

4
Ngoài ra, nếu bạn thực sự muốn chuỗi được định dạng trên nhiều dòng trong c ++ 98, chỉ cần thay thế \ n cho không gian kết thúc trên mỗi đoạn chuỗi được trích dẫn. C ++ 11 nguyên văn vẫn là yêu thích của tôi.
emsr

3
@unwind Lưu ý rằng dòng mới ở cuối dòng nguồn không phải là một phần của chuỗi, nó chỉ bị bỏ qua. Nếu bạn muốn một dòng mới là một phần của chuỗi, bạn cần phải có \ n \ ở cuối dòng.
hyde

2
Có lỗi khó chịu trong Microsoft Visual Studio. Nếu bạn sử dụng dấu gạch chéo ngược ở cuối dòng, thì nó sẽ tự động thụt lề văn bản bên trong chuỗi.
palota

408

Trong C ++ 11, bạn có chuỗi ký tự thô. Sắp xếp giống như ở đây - văn bản trong shell và ngôn ngữ script như Python và Perl và 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";

Tất cả các khoảng trắng và thụt lề và các dòng mới trong chuỗi được giữ nguyên.

Đây cũng có thể là utf-8 | 16 | 32 hoặc wchar_t (với các tiền tố thông thường).

Tôi nên chỉ ra rằng chuỗi thoát, V0G0N, không thực sự cần thiết ở đây. Sự hiện diện của nó sẽ cho phép đặt) "bên trong chuỗi. Nói cách khác, tôi có thể đã đặt

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

(lưu ý thêm trích dẫn) và chuỗi trên vẫn sẽ đúng. Nếu không thì tôi cũng có thể sử dụng

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

Các parens ngay bên trong dấu ngoặc kép vẫn cần thiết.


24
Đây thực sự là những gì tôi muốn, khả năng tránh dấu ngoặc kép, dấu gạch chéo ngược, thoát, và vẫn có dòng mới xuất hiện trong chuỗi thực tế. Điều này rất hữu ích cho mã nhúng (ví dụ: shader hoặc Lua). Thật không may, tất cả chúng ta không sử dụng C ++ - 0x. :-(
mlepage

2
Tôi đã xem xét điều này cho các tập lệnh SQL và Python nhúng. Tôi đã hy vọng cho lợi ích của bạn nếu có thể gcc sẽ cho phép nó lướt qua trong chế độ C ++ 98, nhưng, than ôi, không.
emsr

3
Tôi đã quen với tiếng kêu và gcc. Trong trình biên dịch này, bạn phải đặt cờ cho C ++ 0x hoặc c ++ 11. Trang web của Lookin na MS có vẻ như họ chưa có nghĩa đen. Tôi hiểu rằng MS sẽ phát hành bản cập nhật trình biên dịch mới nhanh hơn khi các tính năng C ++ được triển khai. Tìm kiếm Trình biên dịch Visual C ++ tháng 11 năm 2012 CTP [ microsoft.com/en-us/doad/details.aspx?id=35515] để biết thông tin mới nhất.
emsr

5
@rsethc Chỉ cần sử dụng #if 0... #endifđể nhận xét ra khối mã. Yến cũng vậy.
bobbogo

1
Lấy cảm hứng từ bài thơ Vogon!
Thane Plummer

27

#define MULTILINE(...) #__VA_ARGS__
Tiêu thụ mọi thứ giữa các dấu ngoặc đơn.
Thay thế bất kỳ số lượng ký tự khoảng trắng liên tiếp bằng một khoảng trắng.


1
Bạn có thể thêm \nnếu bạn cần dòng mới
Simon

Lưu ý rằng ` (and hence \ n ) is copied literally, but "` được chuyển đổi thành \". Vì vậy, MULTILINE(1, "2" \3)sản lượng "1, \"2\" \3".
Andreas Spindler

@AndreasSpindler Báo giá và dấu gạch chéo ngược giống nhau được thoát bằng dấu gạch chéo ngược (bổ sung) miễn là chúng xuất hiện bên trong một mã thông báo bằng ký tự chuỗi hoặc ký tự. Không chắc chắn quan điểm của bạn là gì. Việc trích dẫn chưa từng có (gấp đôi hoặc đơn) là bất hợp pháp, do đó, các cơn co thắt không hoạt động, hoặc một số lẻ trong số đó, có lẽ là nhược điểm lớn nhất. +1 dù sao đi nữa. "Lập trình viên thực sự" luôn sử dụng các cơn co thắt theo cặp không có dòng mới can thiệp để cân bằng dấu ngoặc đơn.
Potatoswatter

Vấn đề là ông đã viết "tiêu thụ mọi thứ giữa các dấu ngoặc đơn".
Andreas Spindler

25

Một cách có thể thuận tiện để nhập chuỗi nhiều dòng là sử dụng macro. Điều này chỉ hoạt động nếu dấu ngoặc kép và dấu ngoặc đơn được cân bằng và nó không chứa dấu phẩy 'cấp cao nhất':

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

Được biên dịch với gcc 4.6 hoặc g ++ 4.6, điều này tạo ra: [[Using this trick(,) you don't need to use quotes. Though newlines and multiple white spaces will be replaced by a single whitespace.]]

Lưu ý rằng ,không thể có trong chuỗi, trừ khi nó được chứa trong ngoặc đơn hoặc dấu ngoặc kép. Dấu ngoặc đơn là có thể, nhưng tạo cảnh báo trình biên dịch.

Chỉnh sửa: Như đã đề cập trong các ý kiến, #define MULTI_LINE_STRING(...) #__VA_ARGS__cho phép sử dụng ,.


Đối với một dự án mà tôi muốn đưa một số đoạn mã lua vào c ++, cuối cùng tôi đã viết một tập lệnh python nhỏ, trong đó tôi đã nhập chuỗi multiline và để nó tạo ra tệp nguồn c ++.
bcmpinc

Hoàn hảo cho tôi, thêm một chuỗi danh sách float nhiều dòng từ tệp collada để kiểm tra đơn vị. Tôi không thích đặt dấu ngoặc kép ở mọi nơi, tôi cần một giải pháp sao chép và dán.
Soylent Graham

7
Bạn có thể sử dụng #define MULTILINE(...) #__VA_ARGS__nếu bạn muốn chuỗi của bạn chứa dấu phẩy.
Simon

2
Lưu ý điều này sẽ loại bỏ hầu hết các whitesapce bổ sung (bao gồm tất cả \n\r), đây là loại tiện dụng cho một số trường hợp và gây tử vong cho những người khác.
BCS

17

Bạn cũng có thể làm điều này:

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

2
cảm ơn, điều này thật tuyệt, làm việc ngay cả trong C. rõ ràng, char longString[] = R""""( This is a very long string )""""; cũng làm việc với tôi.
đấu

2
Điều này có bắt đầu và kết thúc chuỗi với một dòng mới không?
Tim MB

1
Đó là một chuỗi ký tự thô . Có sẵn từ C ++ 11.
Mikolasan

15

Bạn chỉ có thể làm điều này:

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

Làm thế nào nó khác với câu trả lời của @ relax?
Sisir

1
@Sisir Tôi đã đăng nó 2 phút trước khi thư giãn.
Eric

Xin lỗi vì đã bỏ lỡ phần đó. +1 của tôi
Sisir

10

Vì một ounce kinh nghiệm đáng giá cả tấn lý thuyết, tôi đã thử một chương trình thử nghiệm nhỏ cho 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"
};

Biên dịch đoạn này với cpp -P -std=c++11 filenameđể tái sản xuất.

Thủ thuật đằng sau #__VA_ARGS____VA_ARGS__không xử lý dấu phẩy. Vì vậy, bạn có thể chuyển nó cho toán tử xâu chuỗi. Các khoảng trắng ở đầu và cuối được cắt bớt và các khoảng trắng (bao gồm cả dòng mới) giữa các từ được nén thành một khoảng trắng sau đó. Dấu ngoặc cần được cân bằng. Tôi nghĩ rằng những thiếu sót này giải thích lý do tại sao các nhà thiết kế của C ++ 11, mặc dù #__VA_ARGS__, đã thấy sự cần thiết của chuỗi ký tự thô.


9

Chỉ cần làm sáng tỏ một chút về nhận xét của @ emsr trong câu trả lời của @ relax, nếu một người không đủ may mắn để có trình biên dịch C ++ 11 (giả sử GCC 4.2.1) và người ta muốn nhúng các dòng mới vào chuỗi (hoặc char * hoặc chuỗi lớp), người ta có thể viết một cái gì đó như thế này:

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

Rất rõ ràng, đúng, nhưng nhận xét ngắn của @ emsr đã không nhảy vào tôi khi tôi đọc điều này lần đầu tiên, vì vậy tôi phải tự mình khám phá điều này. Hy vọng rằng, tôi đã cứu người khác vài phút.


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

Vui lòng thêm một lời giải thích cho câu trả lời của bạn và không chỉ là đoạn mã
Geordie

-1

Tùy chọn 1. Sử dụng thư viện boost, bạn có thể khai báo chuỗi như bên dưới

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

Tùy chọn 2. Nếu boost không có sẵn trong dự án của bạn, bạn có thể sử dụng std :: string_view () trong C ++ hiện đại.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.