Кодування Unicode для рядкових літералів в C ++ 11


85

Після відповідного запитання я хотів би запитати про нові типи символів і рядкових літералів у C ++ 11. Здається, що зараз у нас є чотири типи символів і п’ять типів рядкових літералів. Типи персонажів:

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

І рядкові літерали:

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)

Питання в наступному: Чи можна \x/ \u/ \Uпосилання на символи вільно поєднувати з усіма типами рядків? Чи всі типи рядків мають фіксовану ширину, тобто масиви містять рівно стільки елементів, скільки відображається в літералі, або \x/ \u/ \Uпосилання розширюються до змінної кількості байтів? Чи мають u""і u8""рядки семантику кодування, наприклад, чи можу я сказати char16_t x[] = u"\U0010FFFF", і кодова точка, яка не є BMP, кодується у двоодиничну послідовність UTF16? І так само для u8? В (1), чи можу я писати самотні сурогати \u? Нарешті, чи відомо будь-якій з рядкових функцій, що кодують (тобто вони знають символи та можуть виявити недійсні послідовності байтів)?

Це трохи відкрите питання, але я хотів би отримати якомога повніше уявлення про нове кодування UTF та засоби введення нового C ++ 11.


4
GCC кодується u"\U0010FFFF"у сурогатну пару.
kennytm

Відповіді:


57

Чи можна посилання на символи \ x / \ u / \ U вільно поєднувати з усіма типами рядків?

No. \xможна використовувати в будь-чому, але \uі \Uможна використовувати лише в рядках, спеціально кодованих UTF. Однак, для будь-якого кодованого UTF рядка, \uі \Uможе використовуватися як вам зручно.

Чи всі типи рядків мають фіксовану ширину, тобто масиви містять рівно стільки елементів, скільки відображається в літералі, або посилання \ x / \ u / \ U розширюються до змінної кількості байтів?

Не так, як ти маєш на увазі. \x,, \uі \Uперетворюються на основі кодування рядка. Кількість значень цих "одиниць коду" (з використанням термінів Unicode. A char16_t- це одиниця коду UTF-16) залежить від кодування вміщуваного рядка. Буквал u8"\u1024"створить рядок, що містить 2 chars плюс нульовий термінатор. Буквал u"\u1024"створить рядок, що містить 1 char16_tплюс нульовий термінатор.

Кількість використовуваних одиниць коду базується на кодуванні Unicode.

Чи мають рядки u "" та u8 "" семантику кодування, наприклад, чи можу я сказати char16_t x [] = u "\ U0010FFFF", і кодова точка, яка не є BMP, кодується у послідовність UTF16 із двох одиниць?

u""створює кодований рядок UTF-16. u8""створює кодований рядок UTF-8. Вони будуть кодовані відповідно до специфікації Unicode.

В (1), чи можу я писати самотні сурогати з \ u?

Абсолютно не. Специфікація прямо забороняє використовувати сурогатні пари UTF-16 (0xD800-0xDFFF) як кодові точки для \uабо \U.

Нарешті, чи відомо будь-якій з рядкових функцій, що кодують (тобто вони знають символи та можуть виявити недійсні послідовності байтів)?

Абсолютно не. Ну, дозвольте мені переформулювати це.

std::basic_stringне має справу з кодуваннями Unicode. Вони, безсумнівно, можуть зберігати кодовані UTF рядки. Але вони можуть думати тільки про них , як послідовності char, char16_tабо char32_t; вони не можуть сприймати їх як послідовність кодових точок Unicode, кодованих за допомогою певного механізму. basic_string::length()поверне кількість одиниць коду, а не кодових очок. І очевидно, що стандартні функції бібліотеки рядків C абсолютно марні

Слід зазначити, однак, що "довжина" для рядка Unicode не означає кількість кодових точок. Деякі кодові точки поєднують "символи" (невдале ім'я), які поєднуються з попередньою кодовою точкою. Отже, декілька кодових точок можуть відображати один візуальний символ.

Iostreams насправді може читати / писати значення, кодовані Unicode. Для цього вам доведеться використовувати локаль, щоб вказати кодування та правильно ввести його в різні місця. Це легше сказати, ніж зробити, і я не маю на собі коду, щоб показати вам, як.


7
@Philipp: Ні, вони не є. Юнікод спеціально резервує їх для сурогатів UTF-16. І, як зазначено, специфікація C ++ 0x говорить, що компіляція не вдасться, якщо ви спробуєте призначити кодову точку в цьому діапазоні.
Nicol Bolas

12
Ваше посилання доводить, що це кодові точки. Якщо ви не довіряєте Вікіпедії, прочитайте визначення 9 та 10 у розділі 3 стандарту. Однак сурогатні кодові точки в рядкових літералах заборонені в C ++ 0x правилом § 2.4 / 2.
Філіпп

1
Після прочитання я також підтверджую, що сурогатні кодові точки приймаються в рядкових літералах.
Джордж Куртіс,

У C11 \xне можна використовувати ні з чим, наприклад U + 1F984 не працюватиме з префіксом \ x \uі \Uне може використовуватися з контрольними символами ASCII, принаймні в Clang.
MarcusJ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.