2012-10-28 13 views
6

Piszę parsera JSON w C++ i jestem w obliczu problemu podczas analizowania ciągów JSON:Jak obsługiwać wartości Unicode w ciągach JSON?

Specyfikacja JSON stwierdza, że ​​ciągi JSON może zawierać znaki Unicode w postaci:

"here comes a unicode character: \u05d9 !" 

My JSON parser próbuje odwzorować łańcuchy JSON na std::string, więc zazwyczaj jeden znak ciągów JSON staje się jednym znakiem std::string. Jednak dla tych znaków Unicode, ja naprawdę nie wiem, co robić:

Czy mogę po prostu położyć surowe wartości bajtów w moim std::string tak:

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

Albo należy interpretować dwa znaki z biblioteka taka jak iconv i zamiast tego zapisuje wynik zakodowany w UTF-8 w moim ciągu?

Czy należy używać std::wstring do przechowywania wszystkich znaków? Co wtedy w systemach * NIX, gdzie wchar_t ma 4 bajty?

Czuję, że coś jest nie tak w moich rozwiązaniach, ale nie rozumiem co. Co powinienem zrobić w tej sytuacji?

+0

Jeśli wchar_t ma długość 4 bajtów, można po prostu zerować ... Ponadto UTF-8 nie oznacza znaków 8-bitowych. Dane spoza zestawu ASCII będą również przechowywane w wielu bajtach w kodowaniu UTF-8. –

+0

@ H2CO3: Oczywiście. http://json.org stwierdza, że ​​ciąg * może zawierać ** dowolny znak UNICODE **, ale nie mówi, czy te ciągi znaków są kodowane w UTF-8 czy UTF-16. Wydaje mi się, że jest to kodowanie UTF-8 ze specjalną reprezentacją dla znaków UTF-16. Jednym z celów mojego pytania jest również zapewnienie tego. – ereOn

+3

Nie ma czegoś takiego jak "znaki UTF-16". Istnieją znaki Unicode, które nie są częścią ASCII, i są kodowane przy użyciu wielu bajtów również w UTF-8, UTF-16 i UTF-32. Ciągi złożone z wielobajtowych ciągów znaków w UTF-16 i UTF-32 są wygodne, aby wszystkie postaci miały taką samą długość. –

Odpowiedz

11

Po pewnym kopania i dzięki H2CO3's comments i Philipp's comments, w końcu mógł zrozumieć, jak to ma działać:

Czytając RFC4627 sekcja 3. Encoding:

  1. Kodowanie

    Tekst JSON MUSI być zakodowany w Unicode. Domyślne kodowanie to
    UTF-8.

    Ponieważ pierwsze dwa znaki tekstu JSON zawsze będzie ASCII znaki [RFC0020], możliwe jest określenie, czy oktet
    strumień UTF-8 UTF-16 (BE lub LE) lub UTF -32 (BE lub LE), wyszukując
    według wzorca zer w pierwszych czterech oktetach.

    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 
    

Wygląda więc na to strumień oktet JSON mogą być zakodowane w UTF-8, UTF-16 lub UTF-32 (zarówno w ich być albo LE wariantów dla dwóch ostatnich).

Raz, że jest jasne, Section 2.5. Strings wyjaśnia, jak obsługiwać te wartości \uXXXX w ciągi JSON:

Każda postać może być uciekł. Jeżeli znak jest podstawowym
Wielojęzycznego płaszczyźnie (U + 0000 U + FFFF), to może być
reprezentowane jako sekwencja sześciu znaków: odwrotny solidusu, po
przez małej litery U, a następnie cztery cyfry szesnastkowe kodujące punkt kodowy znaku. Litery heksadecymalne A mogą być wielkimi lub małymi literami. Tak więc, na przykład, ciąg znaków zawierający
tylko jeden znak rewersyjnego solidus może być reprezentowany jako
"\ u005C".

Bardziej szczegółowe wyjaśnienia dotyczące znaków spoza zakresu Basic Multilingual Plane.

Aby uciec rozszerzony znak, który nie jest w podstawowe Multilingual Samolot, postać jest reprezentowany jako ciąg dwunastu znaków,
kodującego UTF-16 zastępczą parę. Na przykład ciąg
zawierający tylko znak G-klucz (U + 1D11E) może być reprezentowany jako
"\ uD834 \ uDD1E".

Mam nadzieję, że to pomoże.

+0

Czy to działa? Kiedy umieszczam moje Wstring jako L "{\" type \ ": \" string \ ", \" value \ ": \" \\ u9CE5 \ "}, \ n", wcout pokazuje \ u9CE5 dla wyjścia w tej linii . – Michele

2

Gdybym był tobą, użyłbym std :: string do przechowywania tylko UTF-8 i UTF-8. Jeśli przychodzący tekst JSON nie zawiera żadnych sekwencji \ uXXXX, std :: string może być używany jako is, byte to byte, bez jakiejkolwiek konwersji.

Kiedy parsujesz \ uXXXX, możesz go po prostu odszyfrować i przekonwertować na UTF-8, skutecznie traktując go tak, jakby był to prawdziwy znak UTF-8 na swoim miejscu - to jest to, co i tak robi większość parserów JSON (libjson na pewno).

To prawda, że ​​przy takim podejściu czytanie JSON-a przy pomocy \ uXXXX i natychmiastowe odrzucanie go z powrotem do biblioteki może spowodować utratę sekwencji \ uXXXX i zastąpienie ich prawdziwymi reprezentacjami UTF-8, ale kto naprawdę to obchodzi? Ostatecznie wynik netto jest wciąż taki sam.

+0

Sekwencje specjalne "\ u" oznaczają jednostki kodowe UTF-16, więc nie można ich po prostu rozszyfrować, nie patrząc na co najmniej dwie sekwencje specjalne. – Philipp

+0

@Philipp: taki wstyd też ... byli tacy bliscy. –

Powiązane problemy