UTF‑16
UTF‑16 (ang. Unicode Transformation Format – 16‑bit) jest jedną z trzech najpopularniejszych metod kodowania znaków w standardzie Unicode. Stosuje się go do reprezentacji kodowania znaków w postaci 16‑bitowych jednostek kodowych (słówek), które mogą być jedną lub dwiema takimi jednostkami, w zależności od położenia znaku w przestrzeni kodowej Unicode.
Historia
Uzasadnieniem wprowadzenia UTF‑16 była potrzeba zapewnienia jednolitego i wydajnego kodowania dla języków wymagających ponad 8 bitów na znak, ale jednocześnie zachowanie względnej kompatybilności z istniejącymi systemami 16‑bitowymi. Standard ten został opisany po raz pierwszy w Unicode 2.0 (1996) i od tego czasu stał się domyślnym formatem wewnętrznym w wielu językach programowania, m.in. w Java i .NET.
Budowa i zasada działania
W UTF‑16 każdy znak Unicode jest reprezentowany za pomocą jednej lub dwóch 16‑bitowych jednostek kodowych:
- Znaki znajdujące się w BMP (Basic Multilingual Plane, zakres U+0000–U+FFFF) są kodowane jednym słowem 16‑bitowym.
- Znaki spoza BMP (U+10000–U+10FFFF) są kodowane przy pomocy par surogatów. Pierwszy słówko (wysoki surogat) mieści się w przedziale D800–DBFF, a drugi (niski surogat) w przedziale DC00–DFFF.
Porządek bajtowy (endianness)
UTF‑16 jest formatem endianness‑zależnym. Aby umożliwić poprawne odczytanie strumienia bajtów, na początku pliku (lub strumienia) może znajdować się znak BOM (Byte Order Mark) o wartości U+FEFF, który wskazuje kolejność bajtów:
- FE FF – kolejność big‑endian (MSB najpierw).
- FF FE – kolejność little‑endian (LSB najpierw).
Zastosowania
UTF‑16 jest wykorzystywany w wielu technologiach i systemach:
- Język programowania Java używa UTF‑16 jako wewnętrznego formatu przechowywania
char. - Platforma .NET definiuje typ
System.Stringjako sekwencję 16‑bitowych kodów UTF‑16. - System operacyjny Windows w niektórych interfejsach API (np.
W‑wersje funkcji) przyjmuje i zwraca łańcuchy w UTF‑16. - Formaty plików multimedialnych i dokumentów, takie jak HTML5 (w atrybucie
charset="utf-16"), XML, JSON (przy odpowiedniej deklaracji), korzystają z UTF‑16.
Porównanie z innymi kodowaniami Unicode
| Kodowanie | Rozmiar jednostki | Zakres BMP | Obsługa znaków poza BMP | Zastosowania typowe |
|---|---|---|---|---|
| UTF‑8 | 1‑4 bajty | 1 bajt (ASCII) – 3 bajty | 4 bajty (sekwencja) | Internet, pliki tekstowe, systemy Unix‑like |
| UTF‑16 | 2 lub 4 bajty (jedno lub dwa słowa 16‑bitowe) | 2 bajty | 4 bajty (para surogatów) | Java, .NET, Windows API |
| UTF‑32 | 4 bajty | 4 bajty | 4 bajty | Systemy wymagające stałej długości kodu |
Implementacje i wsparcie w bibliotekach
Większość współczesnych języków programowania i bibliotek standardowych udostępnia funkcje konwersji między UTF‑16 a innymi formatami:
- W C++ biblioteka
<codecvt>(od C++11) obsługuje konwersję UTF‑16. - W Pythonie typ
strjest wewnętrznie kodowany w UTF‑16 na platformach Windows i UTF‑32 na innych. - W JavaScript ciągi znaków są reprezentowane jako sekwencja 16‑bitowych kod jednostek, co wymaga specjalnych metod (np.
codePointAt) przy obsłudze znaków spoza BMP.
Problemy i ograniczenia
Choć UTF‑16 jest wydajny dla języków, które używają głównie znaków BMP (np. większość języków europejskich i azjatyckich), posiada kilka istotnych wad:
- Rozmiar pamięci nie jest stały – znak spoza BMP zajmuje podwójną ilość pamięci.
- Potrzeba obsługi par surogatów wprowadza dodatkową złożoność przy operacjach na ciągach (np. liczenie znaków, indeksowanie).
- W zależności od endianness może być konieczne użycie BOM, co nie jest wymagane w UTF‑8 i może powodować problemy przy niewłaściwym rozpoznawaniu kolejności bajtów.
Przykłady kodowania
Poniżej przedstawiono kilka przykładów kodowania wybranych znaków w UTF‑16 (big‑endian, bez BOM):
| Znak | U+ kod punktowy | UTF‑16 (hex) | Opis |
|---|---|---|---|
| A | U+0041 | 00 41 | Łaciński wielki znak A |
| Ω | U+03A9 | 03 A9 | Grecka wielka litera omega |
| 𐍈 | U+10348 | D8 00 DF 48 | Runiczny znak „ha” (poza BMP, para surogatów) |