2008-09-28 8 views
12

Używam TinyXML do parsowania/kompilowania plików XML. Teraz, zgodnie z the documentation biblioteka ta obsługuje wielobajtowe zestawy znaków za pośrednictwem UTF-8. Jak dotąd tak dobrze, myślę. Jednak jedynym interfejsem API udostępnianym przez bibliotekę (do pobierania/ustawiania nazw elementów, nazw i wartości atrybutów, ... wszędzie tam, gdzie używany jest ciąg znaków) jest std::string lub const char*. To mnie wątpi w moje rozumienie obsługi wielobajtowego zestawu znaków. W jaki sposób ciąg znaków, który obsługuje tylko znaki 8-bitowe, zawiera znak 16-bitowy (chyba że używa strony kodowej, która neguje żądanie "obsługuje Unicode")? Rozumiem, że teoretycznie można wziąć 16-bitowy punkt kodowy i podzielić go na 2 znaki w postaci std::string, ale nie przekształciłoby to std::string w ciąg znaków "Unicode", spowodowałoby, że byłby on nieważny dla większości celów i może przypadkowo działa, gdy jest zapisany do pliku i wczytany przez inny program.Jak działa obsługa formatu TinyXML w UTF-8?

A może ktoś mi wytłumaczy, w jaki sposób biblioteka może zaoferować "8-bitowy interfejs" (std::string lub const char*) i nadal obsługuje łańcuchy "Unicode"?

(Prawdopodobnie pomieszałem tu trochę terminologii Unicode, przepraszam za wszelkie zamieszanie z tego powodu).

Odpowiedz

8

Po pierwsze, utf-8 jest przechowywany w ciągach znaków const char *, jak powiedział @quinmars. I jest to nie tylko nadzbiór 7-bitowego ASCII (punkty kodowe < = 127 zawsze zakodowane w pojedynczym bajcie, jak same w sobie), ponadto uważamy, że bajty z tymi wartościami nigdy nie są używane jako część kodowania wartości wielobajtowych dla punktów kodowych > = 128. Jeśli widzisz bajt == 44, to jest to znak "<" itd. Wszystkie metazny w XML są w 7-bitowym ASCII. Więc można po prostu parsować XML, zrywając ciągi, w których metachary mówią, wtykając fragmenty (ewentualnie włączając znaki spoza ASCII) w char * lub std :: string, a zwrócone fragmenty pozostają poprawnymi łańcuchami UTF-8, nawet jeśli parser nie znał specyficznie UTF-8.

Co więcej (nie jest to specyficzne dla XML, ale raczej sprytne), nawet bardziej złożone rzeczy genralnie po prostu działają (tm). Na przykład, jeśli leksykograficznie sortujesz kodowanie UTF-8 według bajtów, otrzymujesz tę samą odpowiedź, co w leksykograficznym sortowaniu według punktów kodowych, pomimo zmiany liczby użytych bajtów, ponieważ bajty prefiksu wprowadzają dłuższy (i tym samym o wyższej wartości) kod punkty są liczbowo większe niż te dla mniejszych wartości).

+0

OK, dzięki temu staje się jaśniejsze, ale mimo to - używanie std :: string do reprezentowania w ten sposób danych UTF-8 nie jest tak semantycznie błędne? Nigdy nie będziesz mógł polegać na zawartości tego łańcucha - nie będzie nawet sposobu, aby wiedzieć, jak długo to trwa! (w długości znaków). – Roel

+0

Nawet w przypadku wersji const char * nadal będziesz musiał użyć innej biblioteki, aby pracować niezawodnie z ciągiem znaków. – Roel

+2

Więcej niezdefiniowane niż źle. Metody std :: string (concatenation, iterator slicing, find_ *, etc) nadal działają. length() jest mimo wszystko zdefiniowane jako == size(). Jest nowy warunek wstępny, który kompensuje się na granicy znaku. Jeśli std :: string złożyłaby jakąś obietnicę dotyczącą kodowania, byłoby to błędne, ale tak nie jest. – puetzk

2

UTF-8 jest kompatybilny z 7-bitowym kodem ASCII. Jeśli wartość bajtu jest większa niż 127, oznacza to, że zaczyna się znak wielobajtowy. W zależności od wartości pierwszego bajtu można zobaczyć, ile bajtów zajmie postać, która może wynosić 2-4 bajty, w tym pierwszy bajt (techniczne również 5 lub 6 są możliwe, ale nie są poprawnymi utf-8). Oto dobry zasób o UTF-8: UTF-8 and Unicode FAQ, również strona wiki dla utf8 jest bardzo pouczająca. Ponieważ kodowanie UTF-8 jest oparte na znakach i kończy się na 0, możesz użyć standardowych funkcji ciągu dla większości rzeczy. Jedyną ważną rzeczą jest to, że liczba znaków może się różnić od liczby bajtów. Funkcje takie jak strlen() zwracają liczbę bajtów, ale niekoniecznie liczbę znaków.

0

Przy użyciu od 1 do 4 znaków do kodowania jednego punktu kodu Unicode.