2012-10-26 28 views
10

Sto cercando di implementare il supporto del testo in Windows con l'intenzione di passare anche a una piattaforma Linux in seguito. Sarebbe ideale supportare le lingue internazionali in modo uniforme, ma ciò non sembra essere facilmente realizzabile considerando le due piattaforme in questione. Ho dedicato molto tempo a leggere UNICODE, UTF-8 (e altre codifiche), widechar e simili ed ecco quello che ho capito finora:UNICODE, UTF-8 e Windows p.

UNICODE, come standard, descrive il set di caratteri che sono mappabili e l'ordine in cui si verificano. Mi riferisco a questo come "cosa": UNICODE specifica quello che sarà disponibile.

UTF-8 (e altre codifiche) specificare come: come ciascun carattere verrà rappresentato in un formato binario.

Ora, su Windows, hanno optato per una codifica UCS-2 in origine, ma non sono riusciti a soddisfare i requisiti, quindi UTF-16 è ciò che hanno, che è anche multi-char quando necessario.

ecco il delemma:

  1. di Windows internamente solo fa UTF-16, quindi se si desidera supportare i caratteri internazionali si è costretti a convertirsi al loro versioni WideChar di utilizzare il sistema operativo chiede di conseguenza. Non sembra esserci alcun supporto per chiamare qualcosa come CreateFileA() con una stringa UTF-8 multi-byte e farlo sembrare corretto. È corretto?
  2. In C ci sono alcune funzioni di supporto multibyte (_mbscat, _mbscpy, ecc.), Tuttavia, su Windows, il tipo di carattere è definito come carattere senza segno * per quelle funzioni. Dato che la serie di funzioni _mbs non è un set completo (ad esempio, non esiste _mbstol per convertire una stringa multibyte in una lunga, ad esempio), si è costretti a utilizzare alcune delle versioni char * delle funzioni di runtime, che porta a problemi del compilatore a causa della differenza di tipo firmato/non firmato tra quelle funzioni. Qualcuno ne usa anche quelli? Fai un mucchio di casting per aggirare gli errori?
  3. In C++, std :: string ha iteratori, ma questi sono basati su char_type, non su punti di codice. Quindi, se faccio un ++ su uno std :: string :: iterator, ottengo il prossimo char_type, non il successivo punto di codice. Allo stesso modo, se si chiama std :: string :: operator [], si ottiene un riferimento a un char_type, che ha il grande potenziale di non essere un punto di codice completo. Quindi, come si fa a scorrere una std :: string per punto di codice? (C ha la funzione _mbsinc()).
+1

Non "multi-byte quando necessario". È solo "multi-byte". Non sai se è "necessario" fino a quando non hai iniziato ad elaborarlo. –

+0

Ecco un [post mio] (http://stackoverflow.com/questions/6300804/wchars-encodings-standards-and-portability) su questo argomento; forse è di tuo interesse. Per (3), converti i tuoi dati in UTF-32 (idealmente memorizzati in un 'char32_t'), e quindi i punti di codice equivalgono agli elementi di stringa. –

+3

E ricorda che ci sono pochi motivi validi per iterare una stringa Unicode per punti di codice, perché un grafo può essere rappresentato da più punti di codice (ognuno dei quali può essere più unità di codice in UTF-8 o UTF-16, ma per molti scopi pratici è lo stesso problema due volte). La normalizzazione è una ragione legittima, la codifica per UTF-8 è un'altra, ma queste sono cose per le quali è comunque possibile utilizzare una libreria. –

risposta

6
  1. Corretto. Converterai UTF-8 in UTF-16 per le tue chiamate API Windows.

  2. maggior parte del tempo che si intende utilizzare le funzioni di stringa regolari per UTF-8-strlen, strcpy (sigh), snprintf, strtol. Funzioneranno bene con i caratteri UTF-8. Utilizza char * per UTF-8 o devi eseguire il cast di tutto.

    Si noti che le versioni di sottolineatura come _mbstowcs non sono standard, vengono normalmente denominate senza un carattere di sottolineatura, ad esempio mbstowcs.

  3. È difficile trovare esempi in cui si desidera utilizzare operator[] su una stringa Unicode, il mio consiglio è di starne lontano. Allo stesso modo, l'iterazione di una stringa ha sorprendentemente pochi usi:

    • Se si analizza una stringa (ad esempio, la stringa è C o codice JavaScript, forse si vuole sintassi hilighting) allora si può fare la maggior parte del byte di lavoro -by-byte e ignora l'aspetto multibyte.

    • Se si sta eseguendo una ricerca, lo si farà anche byte per byte (ma ricordarsi di normalizzare prima).

    • Se si cercano interruzioni di parola o limiti di graft grafo, si vorrà utilizzare una libreria come ICU. L'algoritmo non è semplice.

    • Infine, è sempre possibile convertire un blocco di testo in UTF-32 e utilizzarlo in questo modo. Penso che questa sia l'opzione più sicura se si sta implementando uno qualsiasi degli algoritmi Unicode come il confronto o la rottura.

    See: C++ iterate or split UTF-8 string into array of symbols?

2
  1. di Windows internamente solo fa UTF-16, quindi se si desidera supportare i caratteri internazionali si è costretti a convertirsi al loro versioni WideChar di utilizzare il sistema operativo chiede di conseguenza. Non sembra esserci alcun supporto per chiamare qualcosa come CreateFileA() con una stringa UTF-8 multi-byte e farlo sembrare corretto. È corretto?

Sì, è corretto. Le varianti di funzione *A interpretano i parametri di stringa in base alla tabella codici attualmente attiva (che è Windows-1252 nella maggior parte dei computer negli Stati Uniti e nell'Europa occidentale, ma possono spesso essere altre code page) e convertono in UTF-16. Esiste una pagina di codice UTF-8, tuttavia AFAIK non esiste un modo per impostare in modo programmatico la tabella codici attiva (è disponibile GetACP per ottenere la tabella codici attiva, ma non corrispondente SetACP).

  1. In C, ci sono alcuni multi-byte funzioni (_mbscat, _mbscpy, ecc), tuttavia, sulle finestre, il tipo di carattere viene definita come char * per tali funzioni di supporto. Dato che la serie di funzioni _mbs non è un set completo (ad esempio, non esiste _mbstol per convertire una stringa multibyte in una lunga, ad esempio), si è costretti a utilizzare alcune delle versioni char * delle funzioni di runtime, che porta a problemi del compilatore a causa della differenza di tipo firmato/non firmato tra quelle funzioni. Qualcuno ne usa anche quelli? Fai un mucchio di casting per aggirare gli errori?

La mbs* famiglia di funzioni è quasi mai utilizzato, nella mia esperienza. Con l'eccezione di mbstowcs, mbsrtowcs e mbsinit, tali funzioni non sono standard C.

  1. In C++, std :: string trovi iteratori, ma questi sono basati su char_type, non sui punti di codice. Quindi, se faccio un ++ su uno std :: string :: iterator, ottengo il prossimo char_type, non il successivo punto di codice. Allo stesso modo, se si chiama std :: string :: operator [], si ottiene un riferimento a un char_type, che ha il grande potenziale di non essere un punto di codice completo. Quindi, come si fa a scorrere una std :: string per punto di codice? (C ha la funzione _mbsinc()).

penso che mbrtowc(3) sarebbe l'opzione migliore qui per la decodifica di un unico punto di codice di una stringa multibyte.

Nel complesso, penso che la migliore strategia per la compatibilità Unicode multipiattaforma sia quella di fare tutto internamente in UTF-8 usando caratteri a byte singolo. Quando è necessario chiamare una funzione API di Windows, convertirla in UTF-16 e chiamare sempre la variante *W. La maggior parte delle piattaforme non Windows utilizza già UTF-8, quindi è facile utilizzarle.

+0

Sfortunatamente, 'mbrtowc' non decodifica i punti di codice su Windows. –

9

Basta fare UTF-8

Ci sono un sacco di librerie di supporto per UTF-8 in ogni plaftorm, anche alcuni sono multiplaftorm troppo. Le API UTF-16 in Win32 sono limitate e incoerenti come già notato, quindi è meglio tenere tutto in UTF-8 e convertire in UTF-16 all'ultimo momento. Ci sono anche alcuni utili wrapping UTF-8 per l'API di Windows.

Inoltre, nei documenti a livello di applicazione, UTF-8 sta diventando sempre più accettato come standard. Ogni applicazione per la gestione dei testi accetta UTF-8 o, nel peggiore dei casi, mostra "ASCII con alcuni dingbat", mentre ci sono solo poche applicazioni che supportano i documenti UTF-16 e quelli che non lo fanno, lo mostrano come "molto e molto" di spazi bianchi! "

+0

+1 Esattamente quello che stavo scrivendo ... – Damon

+2

+1, per supportare le idee di utf8everywhere.org –

+1

Vorrei aggiungere un riferimento abbastanza buono, perché UTF-8 dovrebbe essere usato ovunque http://utf8everywhere.org/ –