2009-09-30 8 views
11

Mam świadomość, że istnieją różne pytania dotyczące utf-8, głównie o bibliotekach do manipulowania utf-8 'string' jak obiekty.Utf-8 in C++: szybkie i brudne sztuczki

Pracuję jednak nad projektem "umiędzynarodowionym" (strona internetowa, z której koduję backend C++ ... nie pytam), nawet jeśli mamy do czynienia z utf-8, nie potrzebujemy tego tak naprawdę biblioteki. W większości przypadków zwykłe algorytmy std :: string lub algorytmy STL są bardzo wystarczające dla naszych potrzeb, i rzeczywiście jest to celem zastosowania utf-8 w pierwszej kolejności.

Więc, co szukam tutaj jest kapitalizacja „Szybkie & Dirty” sztuczek, które znasz związane z UTF-8 przechowywane jako std :: string (bez const char *, nie wiem Dbaj o kod w stylu c naprawdę mam lepsze rzeczy do roboty niż ciągłe martwienie się o mój rozmiar bufora).

Na przykład o to „Quick & Dirty” podstęp, aby uzyskać liczbę znaków (co jest przydatne wiedzieć, czy będzie pasować w polu wyświetlacza):

#include <string> 
#include <algorithm> 

// Let's remember than in utf-8 encoding, a character may be 
// 1 byte: '0.......' 
// 2 bytes: '110.....' '10......' 
// 3 bytes: '1110....' '10......' '10......' 
// 4 bytes: '11110...' '10......' '10......' '10......' 
// Therefore '10......' is not the beginning of a character ;) 

const unsigned char mask = 0xC0; 
const unsigned char notUtf8Begin = 0x80; 

struct Utf8Begin 
{ 
    bool operator(char c) const { return (c & mask) != notUtf8Begin; } 
}; 

// Let's count 
size_t countUtf8Characters(const std::string& s) 
{ 
    return std::count_if(s.begin(), s.end(), Utf8Begin()); 
} 

W rzeczywistości jeszcze się spotkać USECASE kiedy muszę coś innego niż liczba znaków oraz że std :: string lub algorytmów STL nie ofertę za darmo od:

  • prac sortowania zgodnie z oczekiwaniami
  • żadna część słowa może być mylony jako słowo lub część innego wyrazu

Chciałbym wiedzieć, czy masz inne porównywalne sztuczek, zarówno do liczenia i innych prostych zadań.
Powtarzam, wiem o ICU i Utf8-CPP, ale nie jestem nimi zainteresowany, ponieważ nie potrzebuję pełnowartościowego leczenia (a właściwie nigdy nie potrzebowałem więcej niż liczba znaków).
Powtarzam również, że nie jestem zainteresowany traktowaniem char *, są one staromodne.

+9

Łączenie znaków diakrytycznych nie ma dla ciebie znaczenia? To smutne. Mogą to być postacie według twojego hrabstwa, ale nie zajmują więcej miejsca. Jakakolwiek łącząca się postać. Lub przestrzenie o zerowej szerokości. A sortowanie działa zgodnie z oczekiwaniami? Czego oczekujesz? Jak każdy sortowanie specyficzne dla regionu będzie wiedzieć o sortowaniu, gdy celowo nie użyjesz Unicode (z wyjątkiem pewnego rodzaju tablicy bajtów). – Joey

+0

Zobacz moją edycję, moja aplikacja jest backendem dla strony internetowej, dlatego ustawienia regionalne są w zasięgu przeglądarki. Nigdy nie natknęliśmy się jeszcze na problem łączenia bohaterów, słyszałem o nich, ale nigdy ich nie widziałem, w jakich językach je spotykasz? –

+0

Kilka przypadków użycia, które nie działają dla tekstu w języku innym niż angielski: sortowanie, składanie i dopasowywanie (na przykład niemiecki ß i ss). –

Odpowiedz

5

Ta brudna sztuczka nie zadziała. Po pierwsze, jaka jest wartość maski po tym:

const unsigned char mask = 0x11000000; 
    const unsigned char notUtf8Begin = 0x10000000; 

Być może mieszania reprezentacja hex z binarnym.

Po drugie, jak poprawnie piszesz w kodowaniu utf-8, znak może mieć kilka bajtów. std :: count_if będzie iterować przez wszystkie bajty w sekwencji UTF8. Ale to, czego potrzebujesz, to przyjrzeć się bajtowi wiodącemu dla każdej postaci i pominąć resztę, dopóki nie pojawi się następna postać.

Nie będzie trudno wdrożyć pojedynczy cykl, który wykonuje obliczenia i przeskakuje do przodu za pomocą prostej tabeli maski dla wiodących bajtów.

Na koniec otrzymasz ten sam O (n) do sprawdzania znaków i będzie działać z każdym ciągiem znaków UTF8.

+0

Tak, mam pomieszane maski, przepraszam. Jednak parametr count_if jest nadal poprawny, z wyjątkiem łączącego problemu diakrytycznego. –

+0

Pracowałem na klasie ciągów utf8, gdzie ++ przejdzie poprawnie przez punkty szerokiego kodu i zrezygnuje z tablicy przesunięć, przeskakując z bajtu na bajt. Działa świetnie, ale dla - nie przynosi żadnych korzyści. Kod pedantyczny jest łatwiejszy do utrzymania. – jmucchiello

1

Sortowanie pliku UTF_8 jako pliku binarnego nie sortuje według kolejności 'Unicode'. BOCU-1 zrobiłby to. Jak już powiedziano, twoje "zgodnie z oczekiwaniami" to całkiem niski pasek dla treści nieanglojęzycznych.

0

Obsługujemy to również w ten sposób w OpenLieroX (co jest naprawdę fajne w mojej grze).

Mamy kilka przydatnych funkcji/algorytmów dla takich std :: stringów UTF-8. Zobacz Unicode.h i Unicode.cpp. Na przykład istnieją iteratory UTF8, niektóre proste operatory manipulacji (wstawianie lub usuwanie), konwersje dużych/małych liter, wyszukiwanie niezależne od przypadku, itp.

Ale nie oczekuj, że te funkcje będą zawsze poprawne. Na przykład nie wiedzą tak naprawdę o łączeniu znaków diakrytycznych lub możliwych sposobów kodowania tego samego tekstu.