2010-10-16 28 views
10

Przeczytałem kilka postów na temat najlepszych praktyk dla łańcuchów i kodowania znaków w C++, ale trochę walczę ze znalezieniem ogólnego podejścia, które wydaje mi się dość proste i poprawne. Czy mogę prosić o komentarze na następujące tematy? Jestem skłonny użyć UTF-8 i UTF-32, oraz zdefiniowanie coś takiego:Łańcuchy i kodowanie znaków w C++

typedef std::string string8; 
typedef std::basic_string<uint32_t> string32; 

Klasa string8 byłyby wykorzystywane na UTF-8, posiadające odrębny typ jest tylko przypomnieniem o kodowaniu . Alternatywą byłoby, aby string8 był podklasą std :: string i aby usunąć metody, które nie są całkiem odpowiednie dla UTF-8.

Klasa string32 będzie używana w UTF-32, gdy wymagany jest stały rozmiar czcionki.

Funkcje CPF UTF-8, utf8 :: utf8to32() i utf8 :: utf32to8() lub jeszcze prostsze funkcje opakowania, będą używane do konwersji między tymi dwoma.

+0

Należy zauważyć, że 'string8' jest wciąż tym samym typem co' std :: string'; to po prostu ma inną nazwę. –

+0

Które funkcje 'std :: basic_string' są * w porządku dla UTF-8? – dalle

+0

Co UTF-32 kupuje ponad Wstring/Unicode? btw Visual Studio definiuje 'u16tring' i' u32string'. –

Odpowiedz

9

Jeśli planujesz przesuwać tylko ciągi i nigdy ich nie kontrolować, możesz użyć zwykłego std::string, chociaż jest to praca uboga.

Problem polega na tym, że większość frameworków, nawet standard, ma głupio (jak sądzę) wymuszone kodowanie w pamięci. Mówię głupio, ponieważ kodowanie powinno mieć znaczenie tylko dla interfejsu, a te kodowanie nie jest przystosowane do manipulowania danymi w pamięci.

Ponadto kodowanie jest łatwe (jest to prosta transpozycja CodePoint -> bajty i odwrotnie), podczas gdy główna trudność polega na manipulowaniu danymi.

Przy 8-bitowym lub 16-bitowym ryzyku można przeciąć postać pośrodku, ponieważ ani std::string, ani std::wstring nie są świadomi tego, czym jest postać Unicode. Co gorsza, nawet przy 32-bitowym kodowaniu, istnieje ryzyko oddzielenia znaku od znaków diakrytycznych, które go dotyczą, co również jest głupie.

Obsługa standardu Unicode w języku C++ jest zatem bardzo niedopuszczalna, jeśli chodzi o standard.

Jeśli naprawdę chcesz manipulować ciągiem znaków Unicode, potrzebujesz kontenerowi obsługującemu Unicode. Zwykle używa się biblioteki , chociaż jej interfejs to naprawdę C-ish. Dostaniesz jednak wszystko, czego potrzebujesz do pracy w Unicode z wieloma językami.

+1

Znalazłem twój komentarz o diakrytach trochę przerażający. Jest to w pewnym sensie najbardziej istotne dla tego, co próbuję zrobić, co ma na celu obsłużenie ciągów "poprawnie" w stosunkowo prosty sposób. – nassar

+0

@nassar: niestety jest to przerażające, ponieważ brakuje nam odpowiedniego wsparcia: '( –

+0

ICU ma (między innymi interfejsy w C++) klasę ciągów C++, która współdziała ze std :: string –

1

Opis metody opisanej jako here może być pomocny. To stara, ale użyteczna technika.

1

Nie określono, jakie kodowanie znaków musi być używane dla ciągów, stringów itp. Najczęściej stosowanym jest używanie unicode w szerokich ciągach znaków. Jakie typy i sposoby kodowania powinny być stosowane, zależy od Twoich wymagań.

Jeśli potrzebujesz tylko przekazać dane od A do B, wybierz std :: string z kodowaniem UTF-8 (nie wprowadzaj nowego typu, po prostu użyj std :: string). Jeśli musisz pracować z ciągami (extract, concat, sort, ...) wybierz std :: wstring i jako kodowanie UCS2/UTF-16 (tylko BMP) w systemie Windows i UCS4/UTF-32 w systemie Linux. Korzyścią jest stały rozmiar: każdy znak ma rozmiar 2 (lub 4 dla UCS4) bajtów, podczas gdy std :: string z UTF-8 zwraca nieprawidłowe wyniki length().

Do konwersji można sprawdzić sizeof (std :: wstring :: value_type) == 2 lub 4, aby wybrać UCS2 lub UCS4. Używam biblioteki ICU, ale mogą istnieć proste biblioteki opakowujące.

Opieranie się na std :: string nie jest zalecane, ponieważ element basic_string nie jest przeznaczony (brak wirtualnych elementów itp.). Jeśli naprawdę potrzebujesz swojego własnego typu, takiego jak std :: basic_string < my_char_type> napisz o tym specjalną specjalizację.

nowy standard C++ 0x określa wstring_convert <> i wbuffer_convert <> konwersji z std :: codecvt z wąskiej kodowania do szerokiego zestawu znaków (na przykład UTF-8 do UCS2). Visual Studio 2010 już to zaimplementowało, afaik.

+2

Celowo uniknąłem UCS-2, ponieważ wydaje mi się, że jeśli ktoś ma kłopoty z obsługą kodowania znaków, można równie dobrze zrobić to dobrze i wspierać pełny kod Unicode. (W tym samym czasie szukam czegoś mniej kłopotliwego niż ICU do ogólnego zastosowania.) Jeśli chodzi o UTF-16, to ma on wady zarówno kodowania o zmiennej długości, jak i korzystania z dużej ilości pamięci. Dlatego proponuję użycie kombinacji UTF-8 i UTF-32. – nassar

+0

Punkt zaczerpnięty ze std :: string. Dzięki! – nassar

+1

Myślę, że definiowanie nowego typu nie jest konieczne, ale wiele osób widzących kod std :: string w kodzie będzie zapominać o znakach wielobajtowych i niepoprawnie używać pozycji znaków. Fakt, że jest to UTF-8 może być przenoszony w komentarzach, ale przypomnienie o nazwie typu wydaje się pomocne, ponieważ metody takie jak std :: string :: insert() sugerują moim zdaniem 8-bitowe znaki. – nassar