Mã hóa Unicode cho chuỗi ký tự trong C ++ 11


84

Sau một câu hỏi liên quan , tôi muốn hỏi về các kiểu ký tự chuỗi và ký tự mới trong C ++ 11. Có vẻ như bây giờ chúng ta có bốn loại ký tự và năm loại ký tự chuỗi. Các loại ký tự:

char     a =  '\x30';         // character, no semantics
wchar_t  b = L'\xFFEF';       // wide character, no semantics
char16_t c = u'\u00F6';       // 16-bit, assumed UTF16?
char32_t d = U'\U0010FFFF';   // 32-bit, assumed UCS-4

Và chuỗi ký tự:

char     A[] =  "Hello\x0A";         // byte string, "narrow encoding"
wchar_t  B[] = L"Hell\xF6\x0A";      // wide string, impl-def'd encoding
char16_t C[] = u"Hell\u00F6";        // (1)
char32_t D[] = U"Hell\U000000F6\U0010FFFF"; // (2)
auto     E[] = u8"\u00F6\U0010FFFF"; // (3)

Câu hỏi đặt ra là: Liệu các \x/ \u/ \Unhân vật tài liệu tham khảo một cách tự do kết hợp được với tất cả các loại chuỗi? Có phải tất cả các kiểu chuỗi đều có độ rộng cố định, tức là các mảng chứa chính xác bao nhiêu phần tử xuất hiện trong nghĩa đen, hoặc tham chiếu đến \x/ \u/ \Uđược mở rộng thành một số byte thay đổi? Các chuỗi u""u8""chuỗi có ngữ nghĩa mã hóa không, chẳng hạn như tôi có thể nói char16_t x[] = u"\U0010FFFF", và mã điểm không phải BMP được mã hóa thành một chuỗi UTF16 hai đơn vị? Và tương tự cho u8? Trong (1), tôi có thể viết các đại diện đơn lẻ với \u? Cuối cùng, có bất kỳ mã hóa hàm chuỗi nào không (nghĩa là chúng nhận biết ký tự và có thể phát hiện chuỗi byte không hợp lệ)?

Đây là một câu hỏi mở một chút, nhưng tôi muốn có được bức tranh toàn cảnh nhất có thể về cơ sở mã hóa và loại UTF mới của C ++ 11 mới.


4
GCC không mã hóa u"\U0010FFFF"thành một cặp thay thế.
kennytm

Câu trả lời:


56

Các tham chiếu ký tự \ x / \ u / \ U có thể kết hợp tự do với tất cả các loại chuỗi không?

Không. \xCó thể được sử dụng trong bất kỳ thứ gì, nhưng \u\Uchỉ có thể được sử dụng trong các chuỗi được mã hóa UTF cụ thể. Tuy nhiên, đối với bất kỳ chuỗi được mã hóa UTF nào \u\Ucó thể được sử dụng khi bạn thấy phù hợp.

Có phải tất cả các loại chuỗi đều có độ rộng cố định, tức là các mảng chứa chính xác bao nhiêu phần tử xuất hiện trong chữ hoặc tham chiếu \ x / \ u / \ U được mở rộng thành một số byte thay đổi?

Không phải theo cách của bạn. \x, \u\Uđược chuyển đổi dựa trên mã hóa chuỗi. Số lượng các giá trị "đơn vị mã" (sử dụng thuật ngữ Unicode. A char16_tlà đơn vị mã UTF-16) phụ thuộc vào cách mã hóa của chuỗi chứa. Chữ u8"\u1024"sẽ tạo ra một chuỗi chứa 2 chars cộng với một dấu chấm hết rỗng. Chữ u"\u1024"sẽ tạo ra một chuỗi chứa 1 char16_tcộng với một dấu chấm hết rỗng.

Số lượng đơn vị mã được sử dụng dựa trên bảng mã Unicode.

Chuỗi u "" và u8 "" có ngữ nghĩa mã hóa không, ví dụ: tôi có thể nói char16_t x [] = u "\ U0010FFFF" và mã điểm không phải BMP được mã hóa thành chuỗi UTF16 hai đơn vị không?

u""tạo một chuỗi được mã hóa UTF-16. u8""tạo một chuỗi được mã hóa UTF-8. Chúng sẽ được mã hóa theo đặc tả Unicode.

Trong (1), tôi có thể viết các từ thay thế duy nhất với \ u không?

Tuyệt đối không. Đặc tả rõ ràng cấm sử dụng các cặp thay thế UTF-16 (0xD800-0xDFFF) làm điểm mã cho \uhoặc \U.

Cuối cùng, có bất kỳ mã hóa hàm chuỗi nào không (nghĩa là chúng nhận biết ký tự và có thể phát hiện chuỗi byte không hợp lệ)?

Tuyệt đối không. Vâng, cho phép tôi nói lại điều đó.

std::basic_stringkhông đối phó với các bảng mã Unicode. Chúng chắc chắn có thể lưu trữ các chuỗi được mã hóa UTF. Nhưng họ chỉ có thể nghĩ về chúng như chuỗi char, char16_thoặc char32_t; họ không thể nghĩ về chúng như một chuỗi các điểm mã Unicode được mã hóa bằng một cơ chế cụ thể. basic_string::length()sẽ trả về số lượng đơn vị mã, không phải điểm mã. Và rõ ràng, các hàm chuỗi thư viện chuẩn C hoàn toàn vô dụng

Tuy nhiên, cần lưu ý rằng "độ dài" cho một chuỗi Unicode không có nghĩa là số điểm mã. Một số điểm mã đang kết hợp các "ký tự" (một tên không may), kết hợp với điểm mã trước đó. Vì vậy, nhiều điểm mã có thể ánh xạ đến một ký tự trực quan.

Trên thực tế, Iostream có thể đọc / ghi các giá trị được mã hóa Unicode. Để làm như vậy, bạn sẽ phải sử dụng một ngôn ngữ để chỉ định mã hóa và thấm nhuần nó vào những nơi khác nhau. Điều này nói thì dễ hơn làm và tôi không có bất kỳ mã nào để hướng dẫn bạn cách thực hiện.


7
@Philipp: Không, họ không. Unicode dành riêng chúng cho các đại diện UTF-16. Và, như đã nói, đặc tả của C ++ 0x nói rằng quá trình biên dịch sẽ thất bại nếu bạn cố gắng chỉ định một điểm mã trong phạm vi đó.
Nicol Bolas,

12
Liên kết của bạn chứng minh rằng chúng điểm mã. Nếu bạn không tin tưởng Wikipedia, hãy đọc định nghĩa 9 và 10 trong chương 3 của Tiêu chuẩn. Tuy nhiên, các điểm mã thay thế trong chuỗi ký tự bị cấm trong C ++ 0x theo quy tắc § 2.4 / 2.
Philipp

1
Sau khi đọc, tôi cũng xác nhận rằng các điểm mã Đại diện được chấp nhận trong chuỗi ký tự.
George Kourtis

Trong C11, \xkhông thể được sử dụng với bất cứ điều gì, ví dụ U + 1F984 sẽ không làm việc với các \ x tiền tố, và \u\Ukhông thể được sử dụng với ký tự điều khiển ASCII, ít nhất trong Clang.
MarcusJ
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.