Kodowanie Unicode dla literałów ciągów w C ++ 11

85

Po pokrewnym pytaniu chciałbym zapytać o nowe typy literałów znakowych i łańcuchowych w C ++ 11. Wygląda na to, że mamy teraz cztery rodzaje znaków i pięć rodzajów literałów tekstowych. Typy postaci:

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

I literały ciągów:

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)

Pytanie brzmi: czy odwołania do znaków \x/ \u/ można \Udowolnie łączyć ze wszystkimi typami łańcuchów? Czy wszystkie typy łańcuchów mają stałą szerokość, tj. Tablice zawierają dokładnie tyle elementów, ile występuje w literale, czy też odwołania do \x/ \u/ \Usą rozszerzane do zmiennej liczby bajtów? Czy u""i u8""łańcuchy znaków mają semantykę kodowania, np. Czy mogę powiedzieć char16_t x[] = u"\U0010FFFF", a punkt kodowy inny niż BMP zostaje zakodowany w dwuczęściowej sekwencji UTF16? I podobnie dla u8? W (1), czy mogę pisać samotne surogaty z \u? Wreszcie, czy którakolwiek z funkcji kodowania znaków jest świadoma (tj. Rozpoznają znaki i mogą wykrywać nieprawidłowe sekwencje bajtów)?

To jest trochę otwarte pytanie, ale chciałbym uzyskać możliwie pełny obraz nowego kodowania UTF i funkcji typu nowego C ++ 11.

Kerrek SB
źródło
4
GCC koduje u"\U0010FFFF"w parę zastępczą.
kennytm

Odpowiedzi:

57

Czy odniesienia znakowe \ x / \ u / \ U można dowolnie łączyć ze wszystkimi typami łańcuchów?

Nie \xmożna używać w czymkolwiek, ale \ui \Umożna go używać tylko w łańcuchach, które są specjalnie zakodowane w formacie UTF. Jednak dla dowolnego ciągu zakodowanego w formacie UTF \ui \Umoże być używany według własnego uznania.

Czy wszystkie typy łańcuchów mają stałą szerokość, tj. Tablice zawierają dokładnie tyle elementów, ile występuje w literale, czy też odwołania do \ x / \ u / \ U są rozwijane do zmiennej liczby bajtów?

Nie w sposób, jaki masz na myśli. \x, \ui \Usą konwertowane na podstawie kodowania ciągów. Liczba tych „jednostek kodu” (przy użyciu terminów Unicode. A char16_tjest jednostką kodu UTF-16) zależy od kodowania ciągu zawierającego. Literał u8"\u1024"utworzyłby ciąg zawierający 2 chars plus terminator zerowy. Literał u"\u1024"utworzyłby ciąg zawierający 1 char16_tplus terminator zerowy.

Liczba używanych jednostek kodu jest oparta na kodowaniu Unicode.

Czy łańcuchy u "" i u8 "" mają semantykę kodowania, np. Czy mogę powiedzieć char16_t x [] = u "\ U0010FFFF", a punkt kodowy inny niż BMP zostaje zakodowany w dwuczęściowej sekwencji UTF16?

u""tworzy ciąg zakodowany w formacie UTF-16. u8""tworzy ciąg zakodowany w formacie UTF-8. Zostaną zakodowane zgodnie ze specyfikacją Unicode.

W (1), czy mogę napisać samotne surogaty za pomocą \ u?

Absolutnie nie. Specyfikacja wyraźnie zabrania używania par zastępczych UTF-16 (0xD800-0xDFFF) jako punktów kodowych dla \ulub \U.

Wreszcie, czy którakolwiek z funkcji kodowania znaków jest świadoma (tj. Rozpoznają znaki i mogą wykrywać nieprawidłowe sekwencje bajtów)?

Absolutnie nie. Cóż, pozwól mi to przeformułować.

std::basic_stringnie zajmuje się kodowaniem Unicode. Z pewnością mogą przechowywać ciągi zakodowane w UTF. Ale mogą myśleć tylko o nich jako sekwencje char, char16_tlub char32_t; nie mogą myśleć o nich jako o sekwencji punktów kodowych Unicode, które są zakodowane za pomocą określonego mechanizmu. basic_string::length()zwróci liczbę jednostek kodu, a nie punktów kodowych. I oczywiście, funkcje ciągów w standardowej bibliotece C są całkowicie bezużyteczne

Należy jednak zauważyć, że „długość” łańcucha Unicode nie oznacza liczby punktów kodowych. Niektóre punkty kodowe łączą „znaki” (niefortunna nazwa), które łączą się z poprzednim punktem kodowym. Tak więc wiele punktów kodowych może odpowiadać pojedynczemu znakowi wizualnemu.

Iostreams może w rzeczywistości odczytywać / zapisywać wartości zakodowane w Unicode. Aby to zrobić, będziesz musiał użyć ustawień regionalnych, aby określić kodowanie i odpowiednio nasycić je w różnych miejscach. Łatwiej to powiedzieć niż zrobić, a nie mam na sobie żadnego kodu, aby pokazać ci, jak to zrobić.

Nicol Bolas
źródło
7
@Philipp: Nie, nie są. Unicode specjalnie rezerwuje je dla surogatów UTF-16. I, jak wspomniano, specyfikacja C ++ 0x mówi, że kompilacja zakończy się niepowodzeniem, jeśli spróbujesz wyznaczyć punkt kodowy w tym zakresie.
Nicol Bolas
12
Twój link udowadnia, że są to punkty kodowe. Jeśli nie ufasz Wikipedii, przeczytaj definicje 9 i 10 w rozdziale 3 Standardu. Zastępcze punkty kodowe w literałach łańcuchowych są jednak zabronione w C ++ 0x na mocy reguły § 2.4 / 2.
Philipp,
1
Po przeczytaniu potwierdzam również, że zastępcze punkty kodowe są akceptowane w literałach łańcuchowych.
George Kourtis
W C11 \xnie można go używać z niczym, na przykład U + 1F984 nie będzie działać z prefiksem \ x \ui \Unie może być używane ze znakami sterującymi ASCII, przynajmniej w Clang.
Marcus J,