„Prvním“ počítačům (nebo spíše anglicky hovořícím uživatelům necítícím potřebu psát slova s cizími písmeny :) stačila tabulka znaků o 128 položkách, tzv. ASCII:
Jednotlivé prvky tabulky mají přiřazená čísla 0-127 decimálně (aneb 0-7F hexadecimálně nebo 0-177 osmičkově) – k jejich zachycení v počítači tudíž stačí pouhých 7 bitů z každého bajtu.
Počítače však už standardně používaly bajty, tj. bitů 8. To dávalo k dispozici dalších 128 možných znaků. Není ale divu, že každý si do volného místa vymyslel něco úplně jiného, kupříkladu i grafické prvky:
Pro rozlišení mezi různými rozšířeními v osmém bitu se zavedly tzv. kódové stránky (code pages). Příkladem budiž CP 852 (Latin 2), Windows 1250 (Central Europe), ISO/IEC 8859-5 (Cyrillic).
Alespoň že se všichni shodli, že prvních 128 znaků bude staré dobré ASCII – pokud jste nevěděli, v jaké CP byl dokument uložen, pořád jste přečetli alespoň anglickou abecedu a další základní znaky z ASCII-rozsahu. Ovšem všechno ostatní ... škoda mluvit.
Mimochodem – nejen že co jazyk, to vlastní CP. Spíš co výrobce nebo program to vlastní CP *_* Pamětníkům dodnes vstávají vlasy hrůzou na hlavě, když si vzpomenou na různá kódování češtiny.
A nezapomeňme na východní jazyky, kterým pouhých 128/256 znaků na zaznamenání jejich obrázkových písem o desítkách tisíc znaků v žádném případě stačit nemohlo! Ty svůj problém vyřešily použitím tzv. DBCS-systému – něco se zapsalo bajtem jedním, něco (většina) dvěma.
Dlouho přehlížený problém, který se provalil na světlo s příchodem Internetu (a tedy do té doby nevídanou volnou výměnou dokumentů mezi různými počítači a systémy), naštěstí pár osvícenců řešilo už v osmdesátých letech. Výsledkem jejich snažení byla univerzální množina znaků, tzv.
UNICODE
V Unicode'u má každý znak (jehož přesná definice není ani trochu triviální!) přiřazeno jedinečné konkrétní číslo, tzv. code point. Tak kupříkladu latinské A má číslo U+0041 a řecká α zase U+03B1.
Přiřazených znaků je v dané chvíli již přes sto tisíc, tudíž je jasné, že pro jejich zachycení si už dávno nevystačíme ani se dvěma bajty.
Nejjednodušším způsobem jak uložit text v Unicode'u bude asi prostě zapsat jeho code point přímo jako bajty (pro prvních 65536 znaků případ UTF-16). Číhá na nás ale několik zádrhelů:
První problém (pořadí bajtů) byl nuceně vyřešen (téměř) povinným zápisem jisté sekvence bajtů na začátek každého unicodového řetězce, tzv. BOM (byte order mark). Podle jejich pořadí pak program (interpretující danou sekvenci bajtů jako text) pozná, o kterou z obou variant jde.
FE FF
pro UTF-16 a 00 00 FE FF
pro UTF-32. V UTF-8 BOM (který pak je EF BB BF
) spíše překáží – za prvé je tam zbytečný (UTF-8 je sekvence jednotlivých bajtů, takže žádné problémy s pořadím zápisu vícebajtových hodnot nemá) a za druhé s ním spousta programů nepočítá.
Druhý problém si ovšem vyžádal hodně přemýšlení: Jak jednoznačně a výhodně zaznamenat oněch více jak sto tisíc znaků, aby se všechny vešly, ale přitom jsme nespotřebovávali zbytečně moc místa?
Naprosto geniálním řešením (i když východní Asie naše nadšení sdílet nemusí) je kódování UTF-8.
oktet 1 | oktet 2 | oktet 3 | oktet 4 | code point | znaků |
---|---|---|---|---|---|
0xxxxxxx | 0xxxxxxx | 128 | |||
110zzzyy | 10xxxxxx | 00000zzz yyxxxxxx | ? | ||
1110wwww | 10zzzzyy | 10xxxxxx | wwwwzzzz yyxxxxxx | ? | |
11110uuu | 10vvwwww | 10zzzzyy | 10xxxxxx | 000uuuvv wwwwzzzz yyxxxxxx | ? |
PS: Otazníčky v posledním sloupečku jsou pochopitelně úkol na příslušné hodině ^_~ Nicméně přímý převod z bitů na počet znaků je pouze teoretické maximum, které sráží asi tak na polovinu výrazně komplikovanější struktura Unicode'u, než by člověk na první pohled čekal. (Ne všechny dostupné číselné rozsahy jsou totiž použity pro code points, tedy vlastní určení znaku. Navíc se také uplatňuje pravidlo, že je-li možné daný code point v bajtech zapsat vícero způsoby, vybírá se ten kratší, čímž se delší varianta vyřadí z množiny dostupných hodnot.)
Podívejme se na zoubek japonskému znaku 狼
(ookami = vlk) v kódování UTF-8:
Jednotlivé bajty mají následující binární podobu:
Podle algoritmu pro kódování UTF-8 získáme odpovídající číslo do unicodové tabulky:
A decimální 29436
je skutečně codepoint odpovídající v Unicode'u znaku 狼
.
狼
: „狼“
Podívejme se na zoubek českému slovu řeč
v kódování UTF-8:
Písmenu ř
odpovídá sekvence bajtů \xc5\x99
, písmeno e
jako člen spodní části ASCII-tabulky je reprezentováno samo sebou a písmeno č
zabírá poslední dva bajty \xc4\x8d
. Zde můžeme toto rozdělení vykoukat sice přímo, ale správně ho zjistíme až z odpovídající binární podoby:
Podle algoritmu pro kódování UTF-8 získáme pro jednotlivé znaky odpovídající číslo do unicodové tabulky:
Aniž bychom koukali do standardu, jaké znaky těmto unicodovým codepointům odpovídají, můžeme daná čísla přímo použít pro znakové HTML-entity ř e č
: „řeč“
Zatímco české znaky s nabodeníčky v libovolném osmibitovém kódování zabírají samozřejmě právě jeden bajt, v kódování UTF-8 zabírají bajty dva. Podobně asijská písma typicky zapisovaná pomocí dvoubajtových kódování zabírají na každý znak bajty tři.
V reálných textech se ale ukazuje, že rozdíl je zanedbatelný.
Odpověď je dvojí a nehezká:
utf-8
a utf-8-sig
0_o