Codifica Unicode per valori letterali stringa in C ++ 11


85

A seguito di una domanda correlata , vorrei chiedere informazioni sui nuovi tipi di caratteri e stringhe in C ++ 11. Sembra che ora abbiamo quattro tipi di caratteri e cinque tipi di stringhe letterali. I tipi di carattere:

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 le stringhe letterali:

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)

La domanda è questa: i riferimenti ai caratteri \x/ \u/ sono \Uliberamente combinabili con tutti i tipi di stringa? Tutti i tipi di stringa sono a larghezza fissa, cioè gli array contengono esattamente tanti elementi quanti appaiono nel letterale, oppure i riferimenti a \x/ \u/ \Uvengono espansi in un numero variabile di byte? Le stringhe u""e u8""hanno una semantica di codifica, ad esempio posso dire char16_t x[] = u"\U0010FFFF", e il punto di codice non BMP viene codificato in una sequenza UTF16 a due unità? E allo stesso modo per u8? In (1), posso scrivere surrogati solitari con \u? Infine, qualcuna delle funzioni stringa è a conoscenza della codifica (cioè sono in grado di riconoscere i caratteri e possono rilevare sequenze di byte non valide)?

Questa è una domanda un po 'aperta, ma mi piacerebbe ottenere un quadro il più completo possibile della nuova codifica UTF e delle funzionalità di tipo del nuovo C ++ 11.


4
GCC codifica u"\U0010FFFF"in una coppia surrogata.
kennytm

Risposte:


57

I riferimenti ai caratteri \ x / \ u / \ U sono liberamente combinabili con tutti i tipi di stringa?

No. \xpuò essere utilizzato in qualsiasi cosa, ma \ue \Upuò essere utilizzato solo in stringhe con codifica UTF specifica. Tuttavia, per qualsiasi stringa con codifica UTF \ue \Upuò essere utilizzato come meglio credi.

Tutti i tipi di stringa sono a larghezza fissa, ovvero gli array contengono esattamente tanti elementi quanti appaiono nel letterale, oppure i riferimenti \ x / \ u / \ U vengono espansi in un numero variabile di byte?

Non nel modo in cui intendi. \x, \ue \Uvengono convertiti in base alla codifica della stringa. Il numero di questi char16_tvalori di "unità di codice" (utilizzando termini Unicode. A è un'unità di codice UTF-16) dipende dalla codifica della stringa contenente. Il letterale u8"\u1024"creerebbe una stringa contenente 2 chars più un terminatore nullo. Il letterale u"\u1024"creerebbe una stringa contenente 1char16_t più un terminatore nullo.

Il numero di unità di codice utilizzate si basa sulla codifica Unicode.

Le stringhe u "" e u8 "" hanno una semantica di codifica, ad esempio posso dire char16_t x [] = u "\ U0010FFFF" e il punto di codice non BMP viene codificato in una sequenza UTF16 a due unità?

u""crea una stringa codificata UTF-16. u8""crea una stringa codificata UTF-8. Saranno codificati secondo la specifica Unicode.

In (1), posso scrivere surrogati solitari con \ u?

Assolutamente no. La specifica proibisce espressamente di utilizzare le coppie surrogate UTF-16 (0xD800-0xDFFF) come punti di codice per \uo \U.

Infine, qualcuna delle funzioni stringa è a conoscenza della codifica (cioè sono in grado di riconoscere i caratteri e possono rilevare sequenze di byte non valide)?

Assolutamente no. Bene, permettimi di riformularlo.

std::basic_stringnon si occupa delle codifiche Unicode. Certamente possono memorizzare stringhe con codifica UTF. Ma possono solo pensare a loro come sequenze di char, char16_to char32_t; non possono pensarli come una sequenza di punti di codice Unicode codificati con un meccanismo particolare. basic_string::length()restituirà il numero di unità di codice, non i punti di codice. E ovviamente, le funzioni di stringa della libreria standard C sono totalmente inutili

Va notato tuttavia che "lunghezza" per una stringa Unicode non significa il numero di codepoint. Alcuni punti di codice combinano "caratteri" (un nome sfortunato), che si combinano con il punto di codice precedente. Quindi più punti di codice possono essere mappati su un singolo carattere visivo.

Iostream possono infatti leggere / scrivere valori con codifica Unicode. Per fare ciò, dovrai usare una locale per specificare la codifica e inserirla adeguatamente nei vari posti. È più facile a dirsi che a farsi, e non ho alcun codice su di me per mostrarti come.


7
@Philipp: No, non lo sono. Unicode li riserva specificamente per i surrogati UTF-16. E, come affermato, le specifiche di C ++ 0x dicono che la compilazione fallirà se provi a designare un punto di codice in quell'intervallo.
Nicol Bolas

12
Il tuo collegamento dimostra che sono punti di codice. Se non ti fidi di Wikipedia, leggi le definizioni 9 e 10 nel capitolo 3 dello Standard. Tuttavia, i punti di codice surrogati nelle stringhe letterali sono proibiti in C ++ 0x dalla regola § 2.4 / 2.
Philipp

1
Dopo aver letto confermo anche che i punti di codice surrogato sono accettati in stringhe letterali.
George Kourtis

In C11, \xnon può essere utilizzato con nulla, ad esempio U + 1F984 non funzionerà con il prefisso \ x \ue \Unon può essere utilizzato con caratteri di controllo ASCII, almeno in Clang.
MarcusJ
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.