Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Problem z konwersją nieznanych kodowań na UTF8 w bazie SQLITE
nowy_pehapowiec
post
Post #1





Grupa: Zarejestrowani
Postów: 220
Pomógł: 0
Dołączył: 24.08.2009

Ostrzeżenie: (0%)
-----


Dostałem bazę danych w której dane były wpisane w różnych kodowaniach. Część w językach europejskich a cześć w azjatyckich, przy czym teksty powinny zawierać tylko znaki łacińskie. Teksty z bazy są wyświetlane przy użyciu kodowania utf8 ale na niektórych komputerach w miejscach spacji albo przecinków pojawiają się krzaki. Czyli muszę teraz przekonwertować wszystkie wpisy w bazie na utf8. Ale nie znam kodowań źródłowych, część jest w UTF8, cześć w GB2312, część w różnych wersjach ISO (np iso-8859-1).
W dodatku bazą jest SQLITE, która, ponoć domyślnie używa UTF8.

Jak zamienić to kodowanie nie uszkadzając tekstów? Przejrzałem funkcje z pakietu multibyte ale nie działają w 100% dobrze. Jakieś pomysły?


pozdrawiam

Ten post edytował nowy_pehapowiec 18.11.2009, 13:21:53
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi
Zyx
post
Post #2





Grupa: Zarejestrowani
Postów: 952
Pomógł: 154
Dołączył: 20.01.2007
Skąd: /dev/oracle

Ostrzeżenie: (0%)
-----


Istnieje możliwość takiego sprawdzenia. Sekwencje wielobajtowe w UTF-8 zostały tak dobrane, że kontrola błędu jest stosunkowo prosta bez żadnej dodatkowej tablicy znaków (btw. powodzenia z używaniem takowej - standard Unicode liczy miliony pozycji (IMG:style_emoticons/default/smile.gif) ). Będę podawać tutaj wartości bajtów zapisane binarnie, gdyż tam najlepiej to widać (x - dowolna wartość, koduje numer znaku).

0xxxxxxx - normalny znak ASCII z zakresu 0-127.
10xxxxxx - drugi lub każdy kolejny bajt "wyższych" znaków Unicode. Może być poprzedzony jedynie poprawną sekwencją startową UTF-8 lub innym 10xxxxxx. Jeśli jest przed nim coś innego, taki znak jest błędnie zakodowany.

Sekwencje startowe UTF-8 - kodują znaki od numerów 128 w górę.

110xxxxx - sekwencja dwubajtowa. Po niej musi następować JEDEN bajt 10xxxxxx.
1110xxxx - sekwencja trzybajtowa. Po niej muszą następować DWA bajty 10xxxxxx.
11110xxx - sekwencja czterobajtowa...
itd.

Sprawdzanie poprawności można wykonać przy pomocy prostego automatu skończonego (de facto wyrażenie regularne by wystarczyło, ale jak masz jeszcze po drodze poprawiać źle zakodowane znaki, to musisz własny zaklepać). Potrzebna Ci jest pętla, która jedzie po ciągu od początku do końca oraz jedna zmienna w której masz zapisany aktualny stan. Na Wikipedii możesz sobie doczytać, jak taki automat działa, bo tu szkoda na to miejsca. Opiszę jedynie tabelę przejść w postaci

(stan, aktualny znak) -> nowy stan

(domyślny, 0xxxxxxx) -> domyślny
(domyślny, 10xxxxxx) -> błąd_1
(domyślny, 110xxxxx) -> 2b_1
(domyślny, 1110xxxx) -> 3b_1
(domyślny, 11110xxx) -> 4b_1
(domyślny, 111110xx) -> 5b_1
(domyślny, 1111110x) -> 6b_1

Sprawdzanie sekwencji dwubajtowej:

(2b_1, 10xxxxxx) -> domyślny
(2b_1, xxxxxxxx) -> błąd_2

Sprawdzanie dla sekwencji trzybajtowej:

(3b_1, 10xxxxxx) -> 3b_2
(3b_1, xxxxxxxx) -> błąd_2
(3b_2, 10xxxxxx) -> domyślny
(3b_2, xxxxxxxx) -> błąd_2

Analogicznie konstruujesz stany dla sekwencji 4, 5 i 6-bajtowych. Jak dojdziesz do końca, to jest poprawne.

Taki automat sprawdza jedynie poprawność, ty go rozbudujesz o dodatkowy kod:

1. Przy przejściu do stanu "domyślny" przepisujesz znak do bufora $poprawny zawierającego poprawiony ciąg.
2. Przy napotkaniu sekwencji startowej UTF-8, czyścisz bufor $znakUTF i wprowadzasz tam odczytany bajt.
3. W stanach typu 3b_2, 2b_1 itd. czyli tych, co sprawdzają kolejne bajty znaku UTF-8 dodajesz je do bufora $znakUTF. Jeśli to był ostatni bajt danej sekwencji, dodajesz $znakUTF do bufora $poprawny.
4. Przy wejściu do stanu błąd_1 masz symbol z jakiegoś kodowania jednobajtowego (np. ISO-8859-2), który konwertujesz na odpowiadającą mu kilkubajtową sekwencję UTF-8. Sekwencję tę dodajesz do bufora $poprawny i natychmiast przechodzisz do stanu domyślny tak, żeby analiza mogła od kolejnego znaku trwać dalej.
5. Przy wejściu do stanu błąd_2 masz sytuację, gdy sekwencja UTF-8 rozpoczęła się poprawnie, ale w którymś miejscu pojawił się błąd. Wtedy bierzesz każdy bajt ze $znakUTF, traktujesz go jako jakiś symbol w kodowaniu jednobajtowym, konwertujesz na odpowiadającą mu sekwencję UTF-8 i dodajesz ją do bufora $poprawny. Po zakończeniu od razu zmieniasz stan na domyślny, by od następnego znaku rozpocząć dalej normalną analizę.

Oczywiście nic nie zagwarantuje Ci 100% poprawnej konwersji ciągu, w którym masz wymieszany UTF-8 i kodowania jednobajtowe. Jeśli ciąg znaków z przedziału 128-255 przypadkiem będzie tworzyć poprawną sekwencję znaku UTF-8, każdy algorytm, który nie próbuje zrozumieć czytanego tekstu nie zasygnalizuje tego jako błąd. Sytuacja taka jest mało prawdopodobna, ale możliwa.

Ten post edytował Zyx 25.11.2009, 10:31:30
Go to the top of the page
+Quote Post

Posty w temacie


Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 26.12.2025 - 16:29