Dlaczego potrzebujemy Unicode?
W (niezbyt) pierwszych dniach istniało tylko ASCII. To było w porządku, ponieważ wszystko, co kiedykolwiek będzie potrzebne, to kilka znaków kontrolnych, interpunkcja, cyfry i litery, takie jak te w tym zdaniu. Niestety, dzisiejszy dziwny świat globalnej komunikacji i mediów społecznościowych nie został przewidziany i nie jest niczym niezwykłym, aby zobaczyć angielski, العربية, 汉语, עִבְרִית, ελληνικά i ភាសាខ្មែរ w tym samym dokumencie (mam nadzieję, że nie złamałem żadnego starego przeglądarki).
Ale dla argumentu powiedzmy, że Joe Average jest programistą. Podkreśla, że zawsze będzie potrzebował tylko angielskiego i jako taki chce tylko używać ASCII. Może to być w porządku dla użytkownika Joe , ale nie jest to w porządku dla Joe , twórcy oprogramowania . Około połowa świata używa znaków innych niż łacińskie, a używanie ASCII jest prawdopodobnie bez znaczenia dla tych ludzi, a ponadto zamyka swoje oprogramowanie na dużą i rozwijającą się gospodarkę.
Dlatego potrzebny jest zestaw znaków obejmujący wszystkie języki. Tak powstał Unicode. Przypisuje każdemu znakowi unikalny numer zwany punktem kodowym . Jedną zaletą Unicode w porównaniu z innymi możliwymi zestawami jest to, że pierwsze 256 punktów kodowych jest identycznych z ISO-8859-1 , a zatem także ASCII. Ponadto zdecydowana większość powszechnie używanych znaków jest reprezentowana tylko przez dwa bajty w regionie zwanym podstawową płaszczyzną wielojęzyczną (BMP) . Teraz potrzebne jest kodowanie znaków, aby uzyskać dostęp do tego zestawu znaków, a jak zadaje pytanie, skoncentruję się na UTF-8 i UTF-16.
Uwagi dotyczące pamięci
Ile bajtów daje dostęp do znaków w tych kodowaniach?
- UTF-8:
- 1 bajt: standardowy ASCII
- 2 bajty: arabski, hebrajski, większość europejskich skryptów (w szczególności gruziński )
- 3 bajty: BMP
- 4 bajty: wszystkie znaki Unicode
- UTF-16:
- 2 bajty: BMP
- 4 bajty: wszystkie znaki Unicode
Warto teraz wspomnieć, że do znaków spoza BMP należą starożytne skrypty, symbole matematyczne, symbole muzyczne oraz rzadsze znaki chińskie / japońskie / koreańskie (CJK) .
Jeśli będziesz pracował głównie ze znakami ASCII, to UTF-8 z pewnością jest bardziej wydajny pod względem pamięci. Jeśli jednak pracujesz głównie ze skryptami pozaeuropejskimi, użycie UTF-8 może być nawet 1,5 razy mniej wydajne niż UTF-16. W przypadku dużych ilości tekstu, takich jak duże strony internetowe lub długie dokumenty tekstowe, może to mieć wpływ na wydajność.
Podstawy kodowania
Uwaga: jeśli wiesz, jak są kodowane UTF-8 i UTF-16, przejdź do następnej sekcji, aby uzyskać praktyczne zastosowania.
- UTF-8: W przypadku standardowych znaków ASCII (0-127) kody UTF-8 są identyczne. To sprawia, że UTF-8 jest idealny, jeśli wymagana jest kompatybilność wsteczna z istniejącym tekstem ASCII. Inne znaki wymagają od 2-4 bajtów. Odbywa się to poprzez zarezerwowanie niektórych bitów w każdym z tych bajtów, aby wskazać, że jest to część znaku wielobajtowego. W szczególności pierwszym bitem każdego bajtu jest
1
uniknięcie kolizji ze znakami ASCII.
- UTF-16: W przypadku prawidłowych znaków BMP reprezentacja UTF-16 jest po prostu punktem kodowym. Jednak dla znaków spoza BMP UTF-16 wprowadza pary zastępcze . W takim przypadku połączenie dwóch dwubajtowych części mapuje na znak inny niż BMP. Te dwubajtowe części pochodzą z zakresu liczbowego BMP, ale są gwarantowane przez standard Unicode jako niepoprawne jako znaki BMP. Ponadto, ponieważ UTF-16 ma dwa bajty jako podstawową jednostkę, ma na to wpływ endianizm . Aby to zrekompensować, na początku strumienia danych można umieścić znak kolejności zarezerwowanych bajtów, który wskazuje na endianowość. Zatem jeśli czytasz dane wejściowe UTF-16 i nie określono endianizmu, musisz to sprawdzić.
Jak widać, UTF-8 i UTF-16 nie są ze sobą prawie kompatybilne. Więc jeśli wykonujesz operacje we / wy, upewnij się, że wiesz, jakiego kodowania używasz! Więcej informacji na temat tych kodowań można znaleźć w FAQ UTF .
Praktyczne uwagi dotyczące programowania
Typy znaków i ciągów znaków: Jak są one kodowane w języku programowania? Jeśli są to nieprzetworzone bajty, w momencie, gdy spróbujesz wyprowadzić znaki inne niż ASCII, możesz napotkać kilka problemów. Ponadto, nawet jeśli typ znaku jest oparty na UTF, nie oznacza to, że łańcuchy są poprawne UTF. Mogą zezwalać na sekwencje bajtów, które są nielegalne. Ogólnie rzecz biorąc, będziesz musiał użyć biblioteki obsługującej UTF, takiej jak ICU dla C, C ++ i Java. W każdym razie, jeśli chcesz wprowadzić / wyprowadzić coś innego niż domyślne kodowanie, najpierw musisz je przekonwertować.
Zalecane / domyślne / dominujące kodowanie: Gdy ma się wybór, którego UTF ma używać, zwykle najlepiej jest przestrzegać zalecanych standardów dla środowiska, w którym pracujesz. Na przykład UTF-8 dominuje w Internecie, a od HTML5 to jest zalecanym kodowaniem . I odwrotnie, zarówno środowiska .NET, jak i Java są oparte na typie znaków UTF-16. Myląco (i niepoprawnie) często pojawiają się odwołania do „kodowania Unicode”, które zwykle odnosi się do dominującego kodowania UTF w danym środowisku.
Obsługa bibliotek: używane biblioteki obsługują pewnego rodzaju kodowanie. Który? Czy obsługują skrzynki narożne? Ponieważ konieczność jest matką wynalazku, biblioteki UTF-8 będą na ogół poprawnie obsługiwały znaki 4-bajtowe, ponieważ 1, 2, a nawet 3 bajty mogą występować często. Jednak nie wszystkie rzekome biblioteki UTF-16 prawidłowo obsługują pary zastępcze, ponieważ występują one bardzo rzadko.
Liczenie znaków: Istnieje łączenie znaków w Unicode. Na przykład punkt kodowy U + 006E (n) i U + 0303 (łącząca tylda) tworzy ñ, ale punkt kodowy U + 00F1 tworzy ñ. Powinny wyglądać identycznie, ale prosty algorytm zliczania zwróci 2 dla pierwszego przykładu, 1 dla drugiego. To niekoniecznie jest złe, ale może nie być pożądanym rezultatem.
Porównywanie pod względem równości: A, А i Α wyglądają tak samo, ale są to odpowiednio: łaciński, cyrylica i grecki. Masz również przypadki takie jak C i Ⅽ, jedna to litera, a druga cyfra rzymska. Ponadto mamy również do rozważenia łączące postacie. Aby uzyskać więcej informacji, zobacz Zduplikowane znaki w Unicode .
Pary zastępcze: pojawiają się dość często na SO, więc podam tylko kilka przykładowych linków:
Inni ?: