2012-10-28 22 views
6

Sto scrivendo un parser JSON in C++ e sono di fronte a un problema durante l'analisi di stringhe JSON:Come gestire i valori unicode nelle stringhe JSON?

La specifica JSON afferma che le stringhe JSON possono contenere caratteri unicode sotto forma di:

"here comes a unicode character: \u05d9 !" 

mio JSON parser tenta di mappare le stringhe JSON su std::string quindi, in genere, un carattere delle stringhe JSON diventa un carattere di std::string. Tuttavia, per quei caratteri Unicode, io davvero non so cosa fare:

devo solo mettere i valori byte prime nel mio std::string in questo modo:

std::string mystr; 
mystr.push_back('\0x05'); 
mystr.push_back('\0xd9'); 

O devo interpretare i due personaggi con un libreria come iconv e memorizzare il risultato codificato UTF-8 nella mia stringa, invece?

Devo usare uno std::wstring per memorizzare tutti i caratteri? Cosa succede allora su * NIX OS in cui wchar_t ha una lunghezza di 4 byte?

Sento che qualcosa non va nelle mie soluzioni ma non riesco a capire cosa. Cosa dovrei fare in quella situazione?

+0

Se wchar_t è lungo 4 byte, è possibile solo estendere zero ... Inoltre, UTF-8 non significa caratteri a 8 bit. Non ASCII verrà memorizzato utilizzando più byte nella codifica UTF-8. –

+0

@ H2CO3: certo, anzi. http://json.org afferma che una * stringa * può contenere ** qualsiasi carattere UNICODE ** ma non dice se tali stringhe sono codificate UTF-8 o UTF-16. Mi sembra che sia la codifica UTF-8 con una rappresentazione speciale per i caratteri UTF-16. Un obiettivo della mia domanda è anche assicurarmi di ciò. – ereOn

+3

non esiste "caratteri UTF-16". Esistono caratteri Unicode che non fanno parte di ASCII e sono codificati utilizzando più byte in UTF-8, UTF-16 e UTF-32. Le stringhe composte di caratteri multipli di byte multipli in UTF-16 e UTF-32 sono utili per fare in modo che tutti i caratteri abbiano la stessa lunghezza. –

risposta

11

Dopo un po 'di scavo e grazie alla H2CO3's comments e Philipp's comments, finalmente ho potuto capire come questo dovrebbe funzionare:

Leggendo il RFC4627, Sezione 3. Encoding:

  1. Codifica

    Il testo JSON DEVE essere codificato in Unicode. La codifica predefinita è
    UTF-8.

    Dal momento che i primi due caratteri di un testo JSON sarà sempre ASCII caratteri [RFC0020], è possibile determinare se un ottetto
    flusso è UTF-8, UTF-16 (BE o LE), o UTF -32 (BE o LE) guardando
    al modello di valori null nei primi quattro ottetti.

    00 00 00 xx UTF-32BE 
        00 xx 00 xx UTF-16BE 
        xx 00 00 00 UTF-32LE 
        xx 00 xx 00 UTF-16LE 
        xx xx xx xx UTF-8 
    

in modo che appaia un ottetto flusso JSON può essere codificato in UTF-8, UTF-16 o UTF-32 (in entrambi i loro BE o LE varianti, per gli ultimi due).

Una volta che sia chiaro, Section 2.5. Strings spiega come gestire quei \uXXXX valori in stringhe JSON:

Qualsiasi carattere può essere sfuggito. Se il carattere è nella Base
Multilingual Plane (U + 0000 a U + FFFF), allora può essere
rappresentato come una sequenza di sei caratteri: un solidus inversa, seguita
dalla lettera minuscola u, seguita da quattro cifre esadecimali che
codificano il punto di codice del carattere. Le lettere esadecimali A anche se
F possono essere maiuscole o minuscole. Ad esempio, una stringa contenente
un solo carattere di solidus inverso può essere rappresentata come
"\ u005C".

Con spiegazioni più complete per caratteri non nello Basic Multilingual Plane.

Per sfuggire un carattere esteso che non è nella base multilingue aereo, il carattere è rappresentato come una sequenza di dodici caratteri,
codificante la coppia di surrogati UTF-16. Ad esempio, una stringa
contenente solo il carattere G (U + 1D11E) può essere rappresentata come
"\ uD834 \ uDD1E".

Spero che questo aiuti.

+0

Hai funzionato? Quando metto il mio wstring come L "{\" tipo \ ": \" stringa \ ", \" valore \ ": \" \\ u9CE5 \ "}, \ n", wcout mostra \ u9CE5 per l'output in quella linea . – Michele

2

Se fossi in te, userei std :: string solo per memorizzare UTF-8 e UTF-8. Se il testo JSON in entrata non contiene sequenze \ uXXXX, std :: string può essere utilizzato così com'è, da byte a byte, senza alcuna conversione.

quando si analizza \ uXXXX, si può semplicemente decodificarlo e convertirlo in UTF-8, in modo efficace trattandolo come se fosse vero caratteri UTF-8 al suo posto - questo è ciò che la maggior parte dei parser JSON stanno facendo in ogni caso (libjson di sicuro).

Concesso, con questo approccio, leggere JSON con \ uXXXX e scaricarlo immediatamente utilizzando la libreria è probabile che perda le sequenze \ uXXXX e le sostituisca con le loro effettive rappresentazioni UTF-8, ma a chi importa davvero? In definitiva, il risultato netto è ancora esattamente lo stesso.

+0

Le sequenze di escape '\ u' indicano le unità di codice UTF-16, quindi non è possibile decodificarle semplicemente senza guardare almeno due sequenze di escape. – Philipp

+0

@Philipp: un vero peccato ... erano così vicini. –

Problemi correlati