Codificação Unicode para literais de string em C ++ 11

85

Após uma pergunta relacionada , gostaria de perguntar sobre os novos tipos de caracteres e literais de string no C ++ 11. Parece que agora temos quatro tipos de caracteres e cinco tipos de literais de string. Os tipos de personagem:

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

E os literais de string:

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)

A questão é: as referências do caractere / \x/ \upodem \User combinadas livremente com todos os tipos de string? Todos os tipos de string têm largura fixa, ou seja, os arrays contêm exatamente tantos elementos quanto aparecem no literal, ou as referências \x/ \u/ \Usão expandidas em um número variável de bytes? As strings u""e u8""têm semântica de codificação, por exemplo, posso dizer char16_t x[] = u"\U0010FFFF", e o codepoint não BMP é codificado em uma sequência UTF16 de duas unidades? E da mesma forma para u8? Em (1), posso escrever substitutos solitários com \u? Finalmente, alguma das funções de string reconhece a codificação (ou seja, elas reconhecem os caracteres e podem detectar sequências de bytes inválidas)?

Esta é uma questão um pouco aberta, mas gostaria de obter uma imagem o mais completa possível da nova codificação UTF e recursos de tipo do novo C ++ 11.

Kerrek SB
fonte
4
O GCC se codifica u"\U0010FFFF"em um par substituto.
kennytm

Respostas:

57

As referências de caracteres \ x / \ u / \ U podem ser combinadas livremente com todos os tipos de string?

No. \xpode ser utilizado em qualquer coisa, mas \ue \Usó pode ser utilizado em cadeias que são especificamente codificado-UTF. No entanto, para qualquer string codificada em UTF, \ue \Upode ser usado como desejar.

Todos os tipos de string têm largura fixa, ou seja, os arrays contêm exatamente tantos elementos quanto aparecem no literal, ou as referências \ x / \ u / \ U são expandidas em um número variável de bytes?

Não da maneira que você quer dizer. \x, \ue \Usão convertidos com base na codificação da string. O número dessas "unidades de código" (usando termos Unicode. A char16_té uma unidade de código UTF-16) depende da codificação da string que o contém. O literal u8"\u1024"criaria uma string contendo 2 chars mais um terminador nulo. O literal u"\u1024"criaria uma string contendo 1 char16_tmais um terminador nulo.

O número de unidades de código usado é baseado na codificação Unicode.

As strings u "" e u8 "" têm semântica de codificação, por exemplo, posso dizer char16_t x [] = u "\ U0010FFFF", e o codepoint não BMP é codificado em uma sequência UTF16 de duas unidades?

u""cria uma string codificada em UTF-16. u8""cria uma string codificada em UTF-8. Eles serão codificados de acordo com a especificação Unicode.

Em (1), posso escrever substitutos solitários com \ u?

Absolutamente não. A especificação proíbe expressamente o uso de pares substitutos UTF-16 (0xD800-0xDFFF) como pontos de código para \uou \U.

Finalmente, alguma das funções de string reconhece a codificação (ou seja, elas reconhecem os caracteres e podem detectar sequências de bytes inválidas)?

Absolutamente não. Bem, deixe-me reformular isso.

std::basic_stringnão lida com codificações Unicode. Eles certamente podem armazenar strings codificadas em UTF. Mas eles só podem pensar neles como seqüências de char, char16_tou char32_t; eles não podem pensar neles como uma sequência de pontos de código Unicode que são codificados com um mecanismo específico. basic_string::length()retornará o número de unidades de código, não pontos de código. E, obviamente, as funções de string da biblioteca padrão C são totalmente inúteis

Deve-se notar, entretanto, que "comprimento" para uma string Unicode não significa o número de pontos de código. Alguns pontos de código combinam "caracteres" (um nome infeliz), que se combinam com o ponto de código anterior. Assim, vários pontos de código podem ser mapeados para um único caractere visual.

Iostreams pode, de fato, ler / gravar valores codificados em Unicode. Para fazer isso, você terá que usar uma localidade para especificar a codificação e inseri-la adequadamente nos vários lugares. É mais fácil falar do que fazer, e não tenho nenhum código para mostrar como.

Nicol Bolas
fonte
7
@Philipp: Não, não são. O Unicode reserva-os especificamente para substitutos UTF-16. E, como declarado, a especificação do C ++ 0x diz que a compilação falhará se você tentar designar um ponto de código nesse intervalo.
Nicol Bolas
12
Seu link prova que eles são pontos de código. Se você não confia na Wikipedia, leia as definições 9 e 10 no capítulo 3 do Padrão. No entanto, pontos de código substitutos em literais de string são proibidos em C ++ 0x pela regra § 2.4 / 2.
Philipp
1
Depois de ler, confirmo também que os pontos de código substituto são aceitos em literais de string.
George Kourtis
Em C11, \xnão pode ser usado com nada, por exemplo U + 1F984 não funcionará com o prefixo \ x \ue \Unão pode ser usado com caracteres de controle ASCII, pelo menos no Clang.
MarcusJ