Znaki, punkty kodowe i bajty

Unicode nadaje każdemu znakowi każdego pisma numer, punkt kodowy, zapisywany jako U+ i cyfry szesnastkowe: A to U+0041, ą to U+0105, znak euro U+20AC, uśmiechnięta buźka U+1F600. Pozycji jest ponad milion, z czego około 150 000 jest używanych.

Punkt kodowy trzeba potem zamienić na bajty. UTF-8, kodowanie sieci, używa od jednego do czterech bajtów: jednego dla ASCII, dwóch dla liter z ogonkami i akcentami, trzech dla prawie całej reszty, czterech dla emoji i rzadkich symboli. UTF-16, używane przez JavaScript, Javę i Windows, używa dwóch bajtów albo pary zastępczej z czterech.

Dlatego długość napisu zależy od tego, co się liczy: "😀".length w JavaScripcie to 2, w UTF-8 znak zajmuje 4 bajty, a dla oka jest jeden. A litera z akcentem może być jednym punktem kodowym albo literą ze złożonym znakiem diakrytycznym: wyglądają tak samo, ale nie są takie same.

Częste błędy

  • Obcinanie napisu UTF-8 po stałej liczbie bajtów: można przeciąć znak w połowie.
  • Liczenie znaków przez .length w JavaScripcie: emoji i znaki spoza płaszczyzny podstawowej liczą się podwójnie.
  • Porównywanie tekstów bez normalizacji: gotowe ą i a z dołączonym ogonkiem są dla komputera różne.

Najczęstsze pytania

Czym różni się Unicode od UTF-8?

Unicode to lista znaków z ich numerami; UTF-8 to jeden ze sposobów zapisu tych numerów w bajtach. Ten sam tekst Unicode można zapisać w UTF-8, UTF-16 lub UTF-32.

Dlaczego widzę dziwne znaki, np. Ä… zamiast ą?

Bo tekst w UTF-8 jest odczytywany jako Windows-1250 lub Latin-1: dwa bajty ą, C4 85, zamieniają się w dwa osobne znaki. Wystarczy zadeklarować właściwe kodowanie.

Jak zapisać znak Unicode w HTML?

Encją numeryczną: ą dziesiętnie lub ą szesnastkowo. Jeśli strona jest w UTF-8, można też wpisać znak bezpośrednio.

Jak działa to obliczenie

UTF-8: do U+007F jeden bajt 0xxxxxxx; do U+07FF dwa bajty 110xxxxx 10xxxxxx; do U+FFFF trzy bajty 1110xxxx 10xxxxxx 10xxxxxx; powyżej cztery bajty 11110xxx i trzy bajty kontynuacji. UTF-16: do U+FFFF jedna jednostka 16-bitowa; powyżej odejmuje się 0x10000, a 20 bitów dzieli na dwa znaki zastępcze: 0xD800 + 10 starszych bitów i 0xDC00 + 10 młodszych.