Jakie są różnice między UTF-8, UTF-16 i UTF-32?
Rozumiem, że wszystkie będą przechowywać Unicode i że każdy używa innej liczby bajtów do przedstawienia znaku. Czy istnieje korzyść z wyboru jednego nad drugim?
Jakie są różnice między UTF-8, UTF-16 i UTF-32?
Rozumiem, że wszystkie będą przechowywać Unicode i że każdy używa innej liczby bajtów do przedstawienia znaku. Czy istnieje korzyść z wyboru jednego nad drugim?
Odpowiedzi:
UTF-8 ma tę zaletę, że znaki ASCII reprezentują większość znaków w bloku tekstu, ponieważ UTF-8 koduje je na 8 bitów (jak ASCII). Korzystne jest również to, że plik UTF-8 zawierający tylko znaki ASCII ma takie samo kodowanie jak plik ASCII.
UTF-16 jest lepszy tam, gdzie ASCII nie dominuje, ponieważ używa głównie 2 bajtów na znak. UTF-8 zacznie używać 3 lub więcej bajtów dla znaków wyższego rzędu, gdzie UTF-16 pozostaje na poziomie zaledwie 2 bajtów dla większości znaków.
UTF-32 obejmie wszystkie możliwe znaki w 4 bajtach. To sprawia, że jest dość wzdęty. Nie mogę wymyślić żadnej korzyści z jego używania.
W skrócie:
wchar_t
domyślnie ma 4 bajty. gcc ma opcję, -fshort-wchar
która zmniejsza rozmiar do 2 bajtów, ale psuje binarną kompatybilność ze standardowymi bibliotekami lib.
UTF-8 ma zmienną liczbę od 1 do 4 bajtów.
UTF-16 ma zmienną 2 lub 4 bajty.
UTF-32 ma ustalone 4 bajty.
Uwaga: UTF-8 może zająć od 1 do 6 bajtów zgodnie z najnowszą konwencją: https://lists.gnu.org/archive/html/help-flex/2005-01/msg00030.html
Unicode definiuje pojedynczy ogromny zestaw znaków, przypisując jedną unikalną wartość całkowitą każdemu symbolowi graficznemu (jest to duże uproszczenie i tak naprawdę nie jest prawdą, ale jest wystarczająco blisko dla celów tego pytania). UTF-8/16/32 to po prostu różne sposoby kodowania tego.
W skrócie, UTF-32 używa 32-bitowych wartości dla każdego znaku. To pozwala im używać kodu o stałej szerokości dla każdego znaku.
UTF-16 domyślnie używa 16-bitów, ale daje to tylko 65 000 możliwych znaków, co jest dalekie od pełnego zestawu Unicode. Dlatego niektóre znaki używają par 16-bitowych wartości.
A UTF-8 domyślnie używa wartości 8-bitowych, co oznacza, że 127 pierwszych wartości są znakami jednobajtowymi o stałej szerokości (najbardziej znaczący bit służy do oznaczenia, że jest to początek sekwencji wielobajtowej, pozostawiając 7 bity dla rzeczywistej wartości znaku). Wszystkie pozostałe znaki są kodowane jako ciągi do 4 bajtów (jeśli pamięć służy).
To prowadzi nas do korzyści. Każda postać ASCII jest bezpośrednio kompatybilna z UTF-8, więc do aktualizacji starszych aplikacji, UTF-8 jest powszechnym i oczywistym wyborem. W prawie wszystkich przypadkach zużywa również najmniej pamięci. Z drugiej strony nie możesz dać żadnych gwarancji co do szerokości znaku. Może mieć szerokość 1, 2, 3 lub 4 znaków, co utrudnia manipulację łańcuchem.
UTF-32 jest przeciwny, zużywa najwięcej pamięci (każdy znak ma stałą szerokość 4 bajtów), ale z drugiej strony wiesz, że każda postać ma tę dokładną długość, więc manipulowanie ciągiem staje się znacznie prostsze. Możesz obliczyć liczbę znaków w ciągu po prostu na podstawie długości w bajtach ciągu. Nie możesz tego zrobić z UTF-8.
UTF-16 to kompromis. Pozwala większości znaków zmieścić się w 16-bitowej wartości o stałej szerokości. Tak długo, jak nie masz chińskich symboli, nut lub niektórych innych, możesz założyć, że każda postać ma szerokość 16 bitów. Zużywa mniej pamięci niż UTF-32. Ale jest pod pewnymi względami „najgorszy z obu światów”. Prawie zawsze zużywa więcej pamięci niż UTF-8, i nadal nie omija problemu, który nęka UTF-8 (znaki o zmiennej długości).
Wreszcie często pomocne jest po prostu skorzystanie z obsługi platformy. Windows używa UTF-16 wewnętrznie, więc w Windows jest to oczywisty wybór.
Linux różni się nieco, ale ogólnie używają UTF-8 do wszystkiego, co jest zgodne z Unicode.
Tak krótka odpowiedź: wszystkie trzy kodowania mogą kodować ten sam zestaw znaków, ale reprezentują każdy znak jako różne sekwencje bajtów.
Unicode jest standardem, a o UTF-x można pomyśleć jako techniczną implementację do niektórych praktycznych celów:
Próbowałem w prosty sposób wyjaśnić moje posty na blogu .
wymaga 32 bitów (4 bajty) do zakodowania dowolnego znaku. Na przykład, aby przedstawić kodowy punkt „A” za pomocą tego schematu, musisz wpisać 65 w 32-bitowej liczbie binarnej:
00000000 00000000 00000000 01000001 (Big Endian)
Jeśli przyjrzysz się bliżej, zauważysz, że najbardziej odpowiednie siedem bitów jest w rzeczywistości tymi samymi bitami, gdy używasz schematu ASCII. Ale ponieważ UTF-32 jest schematem o stałej szerokości , musimy dołączyć trzy dodatkowe bajty. Oznacza to, że jeśli mamy dwa pliki zawierające tylko znak „A”, jeden jest zakodowany w formacie ASCII, a drugi w formacie UTF-32, ich rozmiar będzie wynosił odpowiednio 1 bajt i 4 bajty.
Wiele osób uważa, że ponieważ UTF-32 używa stałej bitowej 32 do reprezentowania punktu kodowego, UTF-16 ma stałą szerokość 16 bitów. ŹLE!
W UTF-16 punkt kodowy może być reprezentowany albo w 16 bitach, albo w 32 bitach. Ten schemat to system kodowania o zmiennej długości. Jaka jest przewaga nad UTF-32? Przynajmniej w przypadku ASCII rozmiar plików nie będzie 4-krotnie większy niż oryginał (ale nadal dwa razy), więc nadal nie jesteśmy kompatybilni wstecznie ASCII.
Ponieważ 7 bitów wystarcza do przedstawienia znaku „A”, możemy teraz używać 2 bajtów zamiast 4, takich jak UTF-32. Będzie to wyglądać jak:
00000000 01000001
Zgadłeś słusznie. W UTF-8 punkt kodowy może być reprezentowany przy użyciu 32, 16, 24 lub 8 bitów, a jako system UTF-16 jest to także system kodowania o zmiennej długości.
Wreszcie możemy przedstawić „A” w taki sam sposób, w jaki reprezentujemy go za pomocą systemu kodowania ASCII:
01001101
Rozważmy chińską literę „語” - jej kodowanie UTF-8 to:
11101000 10101010 10011110
Chociaż jego kodowanie UTF-16 jest krótsze:
10001010 10011110
Aby zrozumieć reprezentację i jej interpretację, odwiedź oryginalny post.
UTF-8 będzie najbardziej efektywny pod względem miejsca, chyba że większość znaków pochodzi z przestrzeni znaków CJK (chińskiej, japońskiej i koreańskiej).
UTF-32 najlepiej nadaje się do losowego dostępu poprzez przesunięcie znaków w tablicy bajtów.
0xxxxxxx
w formacie binarnym. Wszystkie dwubajtowe znaki zaczynają się 110xxxxx
od drugiego bajtu 10xxxxxx
. Powiedzmy, że pierwszy znak dwubajtowej postaci został utracony. Jak tylko zobaczysz 10xxxxxx
bez poprzedzającego 110xxxxxx
, możesz z całą pewnością stwierdzić, że bajt został utracony lub uszkodzony, i odrzucić ten znak (lub ponownie poprosić go z serwera lub cokolwiek innego) i przejść dalej, aż ponownie zobaczysz prawidłowy pierwszy bajt .
Przeprowadziłem kilka testów, aby porównać wydajność bazy danych między UTF-8 i UTF-16 w MySQL.
W UTF-32 wszystkie znaki są kodowane za pomocą 32 bitów. Zaletą jest to, że można łatwo obliczyć długość łańcucha. Wadą jest to, że dla każdego znaku ASCII tracisz dodatkowe trzy bajty.
W znakach UTF-8 zmienna długość, znaki ASCII są kodowane jednym bajtem (osiem bitów), większość zachodnich znaków specjalnych jest kodowana albo w dwóch bajtach, albo w trzech bajtach (na przykład € to trzy bajty), a bardziej egzotyczne znaki mogą zająć do czterech bajtów. Oczywistą wadą jest to, że a priori nie można obliczyć długości łańcucha. Ale kodowanie tekstu alfabetu łacińskiego (angielskiego) zajmuje o wiele mniej bajtów niż w przypadku UTF-32.
UTF-16 ma również zmienną długość. Znaki są kodowane albo w dwóch bajtach, albo w czterech bajtach. Naprawdę nie widzę sensu. Ma tę wadę, że ma zmienną długość, ale nie ma zalet oszczędzania tyle miejsca, co UTF-8.
Z tych trzech najwyraźniej najbardziej rozpowszechniony jest UTF-8.
W zależności od środowiska programistycznego możesz nie mieć nawet wyboru, jakiego kodowania typu danych łańcuchowych użyjesz wewnętrznie.
Ale do przechowywania i wymiany danych zawsze używałbym UTF-8, jeśli masz wybór. Jeśli masz głównie dane ASCII, da ci to najmniejszą ilość danych do przesłania, a jednocześnie będziesz w stanie zakodować wszystko. Optymalizacja pod kątem najmniejszej liczby operacji we / wy jest sposobem na zastosowanie nowoczesnych maszyn.
Jak wspomniano, różnica polega przede wszystkim na wielkości zmiennych podstawowych, które w każdym przypadku stają się większe, aby umożliwić reprezentację większej liczby znaków.
Jednak czcionki, kodowanie i inne rzeczy są wyjątkowo skomplikowane (niepotrzebnie?), Więc do wypełnienia bardziej szczegółowych informacji potrzebny jest duży link:
http://www.cs.tut.fi/~jkorpela/chars.html#ascii
Nie oczekuj, że wszystko zrozumiesz, ale jeśli nie chcesz później problemów, warto dowiedzieć się jak najwięcej, tak wcześnie, jak to możliwe (lub po prostu zachęcić kogoś innego do rozwiązania tego problemu).
Paweł.
Krótko mówiąc, jedynym powodem użycia UTF-16 lub UTF-32 jest odpowiednio obsługa skryptów innych niż angielski i starożytnych.
Zastanawiałem się, dlaczego ktokolwiek zdecydowałby się na kodowanie inne niż UTF-8, skoro jest to oczywiście bardziej wydajne do celów internetowych / programistycznych.
Powszechne nieporozumienie - sufiksowana liczba NIE wskazuje na jej możliwości. Wszystkie obsługują pełny Unicode, tyle że UTF-8 może obsługiwać ASCII za pomocą jednego bajtu, więc jest WIĘCEJ wydajny / mniej uszkodzony dla procesora i przez Internet.
Dobra lektura: http://www.personal.psu.edu/ejp10/blogs/gotunicode/2007/10/which_utf_do_i_use.html i http://utf8everywhere.org