2014-09-29 17 views
6

Sto scrivendo alcune funzioni di conversione stringa simili a atoi() o strtoll(). Volevo includere una versione della mia funzione che accetti un char16_t * o char32_t * invece di un solo char * o wchar_t *.Supporto Unicode C11

La mia funzione funziona correttamente, ma mentre stavo scrivendo mi sono reso conto che non capisco cosa siano char16_t o char32_t. So che lo standard richiede solo che siano un tipo intero di almeno 16 o 32 bit, ma l'implicazione è che sono UTF-16 o UTF-32.

So anche che lo standard definisce un paio di funzioni ma non include alcuna funzione * get o * put (come hanno fatto quando sono state aggiunte in wchar.h in C99).

Quindi mi chiedo: cosa si aspettano che faccia con char16_t e char32_t?

+1

Convertire in UTF-8, cos'altro? – Deduplicator

+0

@Deduplicator: Se è quello che si aspettavano che tu facessi con loro, penseresti che ti avrebbero dato le funzioni per farlo ... –

+0

Hai intenzione di supportare non solo '0..9' (U + 0030 .. U + 0039) (e potenzialmente 'A..Z/a..z', fino al livello più alto consueto, base-36) ma tutti gli altri caratteri contrassegnati come" Numerici "nella tabella Unicode completa pure? "Coz include moduli tipografici (super e pedici, numeri cerchiati fino a 20 (!)) E moduli specifici per lo script (numeri arabi, numeri ebraici), oltre a numeri romani, greco antico e" aste di conteggio "e molto altro ancora. – usr2564301

risposta

9

Questa è una buona domanda senza una risposta apparente.

I tipi e le funzioni uchar.h aggiunte in C11 sono in gran parte inutili. Supportano solo le conversioni tra il nuovo tipo (char16_t o char32_t) e la codifica multibyte specifica della locale, definita dall'implementazione, che non saranno complete a meno che la locale sia basata su UTF-8. Le conversioni utili (da/a wchar_t e da/a UTF-8) non sono supportate. Ovviamente puoi eseguire il rollover per le conversioni da/verso UTF-8 poiché queste conversioni sono specificate al 100% dagli standard RFC/UCS/Unicode pertinenti, ma fai attenzione: la maggior parte delle persone le implementa in modo errato e ha dei bug pericolosi.

Notare che il nuovo compilatore livelli dispone per UTF-8, UTF-16 e UTF-32 letterali (u8, u e U, rispettivamente) sono potenzialmente utili; è possibile elaborare le stringhe risultanti con le proprie funzioni in modi significativi che non dipendono affatto dalle impostazioni locali. Ma il supporto a livello di libreria per Unicode in C11 è, a mio parere, sostanzialmente inutile.

+0

Sapete quanto limita la portabilità ad assumere che la codifica multibyte sia UTF-8? (Voglio dire, è qualcosa di simile a "lo standard consente il complemento non-2" che spesso può essere ignorato nella pratica, o è davvero qualcosa di cui dovrei preoccuparmi?) – mafso

+0

@mafso: Non penso che la rappresentazione * interna * di stringhe come UTF8 è un potenziale problema di portabilità. Ma come farai a visualizzare il tuo testo se non esiste un modo (per definizione) "portatile per mostrare il risultato? – usr2564301

+1

@Jongware: So che non è portatile (in teoria). Questa roba "codifica multibyte specifica della locale" e "codifica di caratteri ampia locale specifica della locale" era standardizzata con C89, un tempo in cui le codifiche Unicode non erano di quell'uso diffuso come lo sono oggi (IIRC non erano nemmeno standardizzato da quel momento). La mia domanda è, se al giorno d'oggi è sicuro assumere le codifiche Unicode _in pratica_. – mafso

3

Verificare se una carta UTF-16 o UTF-32 nell'intervallo ASCII è una delle "solite" 10 cifre, +, - o uno spazio bianco "normale" è facile da eseguire e convertire '0'-'9' in una cifra Dato che, atoi_utf16/32() procede come atoi(). Basta ispezionare un personaggio alla volta.

Test se alcuni altro UTF-16/UTF-32 è una cifra o uno spazio bianco - che è più difficile. Il codice richiederebbe un esteso isspace(), isdigit() che può essere dovuto al passaggio da locale (setlocale()) se sono disponibili le impostazioni internazionali necessarie. (Nota: probabilmente necessario ripristinare locale quando viene eseguita la funzione

Conversione di un personaggio che passa isdigit() ma non è uno dei soliti 10 per il suo valore è problematico ogni modo, che appare non ancora ammesse...

procedura di conversione:

  1. Set locale ad uno corrispondente per UTF-16/UTF-32

  2. Uso isspace() f. o rilevamento dello spazio bianco.

  3. Convertire è un modo simile per your_atof().

  4. Ripristino locale.

+0

E non dimenticare che UTF-16 e UTF-32 hanno entrambe le varianti big-endian e little-endian, e potrebbe interessarti. – JohnH

+0

@JohnH: Come può essere rilevante per UTF-32? – mafso

+1

@mafso Le varianti big/little endian si applicano sia a UTF-16 che a UTF-32. A livello _byte_, i 2 o 4 byte hanno un ordine che erroneamente corrisponde in modo errato all'ordine dei byte del software. Questo può essere risolto usando varie funzioni di riordino dei byte. Con un punto di codice Unicode> = 0x10000 e la codifica è UTF-16, l'ordine sui 2 surrogati UTF-16 si verifica talvolta in ordine big o little endian. Solo uno di questi è corretto (dimenticare quale).Quando viene utilizzato quello errato, dovrebbe essere contrassegnato come un errore di codifica, sebbene alcuni sistemi siano indulgenti (non reclami). – chux

0

Questa domanda può essere un po 'vecchio, ma mi piacerebbe toccare attuare le funzioni con char16_t e char32_t supporto.

Il modo più semplice per eseguire questa operazione è scrivere la funzione strtoull utilizzando il tipo char32_t (chiamarlo come strtoull_c32). Ciò semplifica il parsing unicode perché ogni carattere in UTF-32 occupa quattro byte. Quindi implementare strtoull_c16 e strtoull_c8 convertendo internamente entrambe le codifiche UTF-8 e UTF-16 in UTF-32 e passandole a strtoull_c32.

Onestamente non ho guardato le strutture Unicode nella libreria standard C11, ma se non forniscono un modo adeguato per convertire tali tipi in UTF-32, allora puoi usare una libreria di terze parti per fare la conversione per te .

C'è ICU, che è stato avviato da IBM e quindi adottato dal Consorzio Unicode. È una libreria molto ricca di funzionalità e stabile che esiste da molto tempo.

Ho avviato una libreria UTF (UTFX) per C89 di recente, che è possibile utilizzare anche per questo. È abbastanza semplice e leggero, testato e documentato. Puoi provarlo, oppure usarlo per saperne di più su come funzionano le conversioni UTF.