Uvod
Everyone in the world should be able to use their own language on phones and computers.
Citat koji ste upravo pročitali, preuzet je sa zvaničnog sajta UNICODE konzorcijuma i potcrtava osnovnu ideju koja stoji iza pomenutog standarda, koji korisnicima najrazličitijih računarskih sistema već duže vreme omogućava upravo to - da na različitim uređajima, na različitim operativnim sistemima i u različitim programima, koriste maternji jezik (odnosno, odgovarajuće pismo).
Reklo bi se da je 'nekako' red da početkom treće decenije dvadestog veka situacija bude takva, ali nije uvek bilo tako.
Nekada su "nad mutnom vodom graktale vrane" .....
ASCII - American Standard Code for Information Interchange
Pre nego što je postalo moguće na računarima koristiti "sve" znakove iz bilo kog jezika (kako smo naveli u uvodu), bilo je potrebno uspostaviti sistem koji uopšte omogućava bilo kakvo korišćenje znakova na računarima (a ne brinite, osvrnućemo se malo kasnije i na vrane).
Naravno, da bismo vam još dodatno "zakomplikovali život", pre svega moramo razuemeti kako je uopšte moguće predstavljati znakove na računarima.
Da li računari (uopšte) mogu neposredno razumeti znakove?
Ako ste pročitali naš članak koji je posvećen upotrebi binarnog brojevnog sistema u računarskim sistemima, verujemo da već znate da je ogovor na pitanje iz podnaslova - ne.
Možda to nije "lep" odgovor, ali, u navedenom članku, potrudili smo se da detaljno predočimo našim čitaocima zašto računari ne mogu razumeti dekadni brojevni sistem, pri čemu smo se takođe osvrnuli na očiglednu okolnost da računari zapravo ne razumeju ni binarne "brojeve" - iz čega onda nije teško naslutiti da slova i ostali znakovi 'nemaju prevelike šanse' po pitanju neposrednog predstavljana na računarima.
Međutim, u praktičnom smislu, budući da računari u svojim logičkim kolima prepoznaju dva naponska stanja: "nema napona" i "ima napona", to svakako možemo iskoristiti da preko stanja "nema napona" kodiramo logičke nule, a preko stanja "ima napona", logičke jedinice, što dalje omogućava kreiranje logičkih kola koja su u stanju da operišu nad binarnim brojevima.
Pre uvođenja ASCII standarda - period koji grubo možemo smatrati prvim godinama računarske industrije (druga polovina pedesetih i šezdesete godine dvadesetog veka), znakovi su se na računarima zapisivali na idiosinkratične načine (idiosinkratičan = sebi svojstven), koji nisu bili međusobno usklađeni, što praktično znači da nije bilo moguće razmenjivati teksutalne poruke između različitih računarskih sistema (makar ne bez programa za prevođenje).
U to vreme, kada su računari još uvek u kontekstu šire primene delovali kao nešto iz domena naučne fantastike, nemogućnost međusobne komunikacije računara (donekle) nije bila preveliki problem, ali, budući da se razmišljalo i u budućnosti za koju se već tada očekivalo da će podrazumevati širu rasprostranjenost računara i veći obim komunikacije između računara, zaključeno je da takva budućnost neće biti moguća bez standarda za razmenu poruka između različitih računarskih sistema.
Ukratko (da se vratimo na kodiranje znakova): ako preko naponskih stanja (već "nekako") možemo kodirati brojeve, onda možemo i preko brojeva kodirati znakove ....
Uvođenje ASCII standarda
ASCII (American Standard Code for Information Interchange), je prvi široko rasprostranjen i opšteprihvaćen standard za kodiranje znakova u elektronskoj komunikaciji i kao takav - hardverski podržan od većine (koliko nam je poznato - skoro svih) računara koji su se u međuvremenu pojavili.
Prva specifikacija ASCII standarda je objavljena 1963, ali je ASCII svoj krajnji oblik poprimio krajem šezdesetih godina.
U osnovnom tehničkom smislu, iza ASCII standarda stoji ideja da se svakom velikom i malom slovu engleskog alfabeta, ciframa i drugim pažljivo biranim specijalnim znakovima, dodeli određena vrednost u rasponu od 0 do 127 (naravno, uvek ista - i pri pisanju, i pri čitanju).
ASCII tabela
ASCII tabela sadrži 128 znakova (koje možete videti u donjem formularu), tako da prve 32 pozicije zauzimaju kontrolni znakovi (znakovi koji se ne vide u štampi, ili na ekranu), dok ostale pozicije zauzimaju znakovi koji se mogu videti i predstavljeni su grafičkim simbolima.
Što se tiče kontrolnih znakova koji zauzimaju početne pozicije (i ne vide se u ispisu), izdovjićemo nekoliko uobičajenijih (sa dekadnim kodovima, za lakše snalaženje):
- 13 - carriage return (taster "ENTER")
- 27 - Escape (taster ESC)
- 32 - Space (razmak na tastaturi)
- 8 - Backspace (taster BACKSPACE na tastaturi)
(Za ostale znakove koje prepoznajete od ranije, možete videti grafičke simbole.)
Pravilnosti u dodeljivanju mesta u tabeli ciframa i slovima
ASCII tabela može delovati donekle nasumično na prvi pogled, međutim, zapravo postoji prilično jasna ideja vodilja, makar kada su u pitanju znaci koji označavaju cifre i slova: postaviti cifru 1, veliko i malo slovo 'A' na "prvu" poziciju.
Vidimo u tabeli da navedeni znakovi nisu na prvoj pozicij i jasno je (pre svega) da na istoj poziciji (nikako) ne mogu biti tri znaka, a ne deluje ni da kodni brojevi 48, 65 i 97 mogu imati previše veze sa znakovima '0', 'A' i 'a' (niti da imaju veze sa brojem 1).
Međutim, pažljivijim proučavanjem, zapazićemo red i pravilnosti.
Ako posmatramo zapis cifara preko ASCII tabele (uzećemo samo nekoliko prvih za primer) ....

.... zapažemo da bitovi na najnižim pozicijama odgovaraju vrednostima cifara (uz uključene bitove na višim pozicijama - 32 i 16):
- cifra '0' se zapisuje preko kodne vrednosti 48, što možemo shvatiti kao 48 + 0
- cifra '1' se zapisuje preko kodne vrednosti 49, što možemo shvatiti kao 48 + 1
- cifra '2' se zapisuje preko kodne vrednosti 50, što možemo shvatiti kao 48 + 2
- cifra '3' se zapisuje preko kodne vrednosti 53, što možemo shvatiti kao 48 + 3
Ista ideja stoji i iza zapisa malih slova:

.... gde zapažemo da bitovi na najnižim pozicijama odgovaraju pozicijama znakova u engleskom alfabetu ....
- znak 'A' se zapisuje preko kodne vrednosti 65, što možemo shvatiti kao 64 + 1
- znak 'B' se zapisuje preko kodne vrednosti 66, što možemo shvatiti kao 64 + 2
- znak 'C' se zapisuje preko kodne vrednosti 67, što možemo shvatiti kao 64 + 3
Velika slova takođe se zapisuju po istom principu:

.... gde zapažemo da bitovi na najnižim pozicijama odgovaraju pozicijama znakova u engleskom alfabetu i takođe, da su kodne vrednosti veće za 32 u odnosu na velika slova....
- znak 'a' se zapisuje preko kodne vrednosti 97, što možemo shvatiti kao 64 + 32 + 1
- znak 'b' se zapisuje preko kodne vrednosti 98, što možemo shvatiti kao 64 + 32 + 2
- znak 'c' se zapisuje preko kodne vrednosti 98, što možemo shvatiti kao 64 + 32 + 3
Kada uočimo ovakve pravilnosti, možemo ih koristiti u pisanju programa.
Manipulacija bitovima i drugi programski kodovi za ispis znakova
Manipulacijom bitova (pod uslovom da smo sigurni da je dati znak - ono što bi trebalo da bude), vrlo lako možemo pretvarati velika slova u mala i takođe, od znakova za cifre kreirati odgovarajuće celobrojne vrednosti.
Na primer:
maloSlovo = velikoSlovo | 32; // 'A' => 'a'
velikoSlovo = maloSlovo & ~32; // 'a' => 'A'
cifra = znakZaCifru & 15; // 49 => 1
Kad smo već kod programskih kodova, u C-u je veoma lako dobiti ispis kodne vrednosti znaka:
char c = 'A';
printf("%c\n", c); // A
printf("%d\n", c); // 65
.... a pomenimo i kako se navedeno (uz neke dodatne mogućnosti), može izvesti i preko Javascript-a:
let c = 65;
console.log(`c;`); // A
console.log(c.toString(2)); // 01000001
console.log(c.toString(16)); // 41
console.log(c); // 65
Proširena ASCII tabela / kodne stranice
ASCII tabela je sedmobitna (nasleđe iz starijih vremena), ali se praktično zapisuje preko osam bita (1 bajt), pa je jasno da u takvom zapisu postoji mesta za "još toliko" znakova.
U periodu posle početnog 'uhodavanja' sa ASCII standardom, a pogotovo između početka osamdesetih i sredine devedesetih godina dvadesetog veka, pojavile su se brojne 'varijacije na temu' ASCII tabele.
Neke od tih proširenih tabela samo su dodavale znakove na pozicije preko 127, dok su druge tabele koristile eklektičan pristup koji je podrazumevao i zamenu ponekog znaka iz standardne ASCII specifikacije (koji se već u navedenom periodu sa kraja prošlog veka nisu koristili), drugim znakovima koji su smatrani praktičnijim za upotrebu.
Ovakve tabele nazivaju se još i kodnim stranicama (code page), a za primer ćemo uzeti kodnu stranicu 437, proširenu ASCII tabelu koja je uvedena sa prvobitnim PC računarima, odnosno sa operativnim sistemom DOS:
199 - ╟
200 - ╚
201 - ╔
195 - ├
192 - └
218 - ┌
30 - ▲
31 - ▼
Zarad preglednosti, prikazali smo samo pojednine znakove (a programeri sa podužim stažom, setiće se vremena kada su se ovakvi znakovi koristili za kreiranje prozora u tekstualnom režimu).
Pre nego što konačno pređemo na UNICODE i UTF-8, osvrnućemo se ukratko i na kodne stranice sa znakovima različitih pisama koje možemo smatrati prethodnicima UNICODE-a, standarda koji, kao što je već pomenuto, objedinjuje znakove svih pisama (kao i mnoge druge znakove).
Kodna stranica 1251 (ćirilica)
Kodna stranica (Code Page) 1251, odgovara znakovima srpskog ćiriličnog pisma (zarad preglednosti, i ovde ćemo navesti samo određene znakove) ....
230 - ж
142 - ћ
247 - ч
248 - ш
Kodna stranica 852 (latinica)
Za latinična pisma iz slovesnkih jezika, bila je zadužena kodna strancia 852:
159 - č
158 - ć
231 - š
190 - ž
Kodna stranica 737 (grčki alfabet)
Uzećemo za primer još i Kodnu Stranicu 737, preko koje su definisana grčka slova ....
158 - η
159 - θ
231 - ύ
240 - Ώ
Već preko ovih nekoliko primera nije teško zamključiti da kodne stranice deluju pomalo neorganizovano, kao i to da bilo kakva greška koja bi dovela do pogrešnog odabira kodne stranice, dovodi do toga da tekst postane praktično nečitljiv (greške su svakako manje izražene u slučajevima kada se pomešaju različite verzije latiničnih pisma, dok, ako pomešamo ćirilicu i grčko pismo - nećemo biti "takve sreće").
Naravno, možemo iz sadašnje perspektive gledati na kodne stranice na način kako pojedini ljudi posmatraju fosilne ostatke predaka homo sapiensa, ali, evolucija se ne dešava 'preko noći', nekada nije bilo 'mostova i puteva' i trebalo je ipak vremena i truda da se sve izgradi.
UNICODE
Sada kada razumemo dobru oragnizaciju ASCII standarda kada je u pitanju engleski alfabet, ali i očigledne nedostatke indeksiranja različitih skupova znakova (različitih svetskih pisama), preko proširenih ASCII tabela, jasno je da je bilo potrebno opštije i bolje implementirano rešenje.
UNICODE predstavlja standard iza koga stoji nekoliko osnovnih ideja:
- osnovni cilj je - obuhvatiti sve znakove, iz svih svetskih jezika, odnosno - koliko god je moguće znakova
- svaki znak mora imati jedinstvenu kodnu poziciju - (eng.) code point (što je pristup sličan ASCII standardu)
- UNICODE mora biti potpuno kompatibilan sa ASCII specifikacijom (kodovi znakova iz ASCII tabele odgovaraju kodnim pozicima koji dati znakovi zauzimaju u UNICODE specifikaciji)
UNICODE konzorcijum osnovan je krajem osamdesetih godina dvadesetog veka. Osnivači ovog projekta su programeri Džo Beker (Joe Becker), Li kolins (Lee Collins) i Mark Dejvis (Mark Davis), a podršku pružaju brojni saradnici iz različitih računarskih kompanija (pogotovo onih koje su direktno zainteresovane za održavanje standarda u obradi teksta na računarima).
U početku, specifikacija je obuhvatale nekoliko desetina hiljada znakova (što svakako nije mali broj), ali, već do početka XXI veka, prevaziđen je broj od 100 hiljada znakova ....
....što je zahtevalo 'prepravljanje' tehničkih rešenja za enkodiranje znakova.
Kada smo kod tehničkih rešenja, od svih odlika UNICODE-a koje smo naveli, posebno se ističe očuvanje kompatibilnosti sa ASCII standardom (pri čemu je doneta racionalna i praktična odluka da se ASCII tabela "ne dira" - već samo proširi), što posebno dolazi do izražaja ako se za enkodiranje UNICODE znakova koristi UTF-8 specifikacija (o svemu navedenom ćemo govoriti u nastavku).
Enkodiranje UNICODE znakova
Znakovi se u ukviru UNICODE standarda kodiraju prema dogovoru, tako da svakom znaku odgovara jedinstvena 'kodna pozicija' (code point).
Prvih 127 pozicija zauzimaju redom znakovi iz ASCII tabele.
Zatim slede uobičajenija pisma nalik na engleski alfabet (u koja možemo ubrojati ćirilicu i latinicu, grčki i ruski alfabet), čiji znakovi zauzimaju kodne pozicije relativno blizu početnih ASCII pozicija.
Više pozicije zauzimaju manje uobičajena (ali i dalje široko rasprostranjena) pisma sa velikim brojem znakova (kinesko, japansko, korejsko, indijsko i sl).
Najviše / najudaljenije pozicije zauzimaju najrazličitije vrste specijalnih znakova.
Sledeće pitanje je: kako to sve zapisati, onosno kodirati?
ASCII znakovi zauzimaju 1 bajt (zapravo manje od jednog celog bajta), dok sa UNICODE znakovima, kojih ima mnogo više od 2^7, to nije i ne može biti slučaj.
Na primer, znakovi (uzmimo za primer nekoliko znakova različite "udaljenosti" od ASCCII pozicija) ....
Č - 268
∑ - 8721
✅ - 9989
🙂 - 128578
.... shodno svojim kodnim pozicijama, očigledno zahtevaju više od jednog bajta za zapis (dva, tri, ili četiri).
Prvobitno rešenje (UCS-2), koristilo se pre 2000. - u vreme dok je ukupan broj kodnih pozicija bio manji od 2^16 (65536), ali je taj broj ubzo prerastao prvobitne okvire ....
UNICODE Transformation Format (UTF-16 - UTF-32 - UTF-8)
Kada je broj kodnih pozicija prevazišao smeštajni kapacitet od 16 bita, uveden je standard UTF-16, koji predstavlja proširenje UCS-2 specifikacije, a potom i standardi UTF-32 (koji koristi 4 bajta), kao i UTF-8.
U nastavku ćemo posvetiti pažnju tehničkim detaljima ovih metoda za kodiranje znakova, njihovim prednostima i nedostacima, kao i oblastima primene.
Iako u naslovu članka stoji (samo) UTF-8, standardu UTF-16 ćemo svakako posvetiti svu dužnu pažnju
UTF-16
UTF-16 je unapređenje standarda UCS-2, koji je podrazumevao je korišćenje dva bajta za zapis svakog znaka.
Upravo je to osnovna ideja koja stoji i iza UTF-16 zapisa, ali, pretpostavka da će ((za)uvek) biti dovoljno koristiti 2^16 znakova je, kao što smo već nagovestili, odavno opovrgnuta.
Kada su u pitanju niže pozicije, za UTF-16 zapis znaka (baš kao i u slučaju starog standarda UCS-2), izdvojićemo dva bajta, a razliku predstavljaju pozicije preko 65536, u kom slučaju UTF-16 zapis koristi dodatna dva bajta.
Primera radi, znak 'Č' (koji smo već pominjali), čija je kodna pozicija 268, u UTF-16 enkodiranju koristi dva bajta i ima sledeći raspored bitova:

Za ovakav znak, korišćenje dva bajta je racionalan i optimalan izbor.
Ako isti princip primenimo na znak 'A', čija je kodna pozicija ("i dalje") 65 ....

.... vidimo da je zapis (naravno) moguć, ali da pri tom dolazi do (reklo bi se - nepotrebnog) dupliranja memorijskog zauzeća.

Na slici vidimo da prvi bajt (praktično) ne igra nikakvu ulogu, ali, iako UTF-16 dozvoljava korišćenje dodatne grupe od dva bajta, nije moguće selektivno koristiti samo jedan bajt za znakove sa prvih 127 pozicija.
Sada možemo uzeti u obzir i kodne pozicije koje ne mogu stati u 16 bita ....
Zapis kodnih pozicija većih od 65535 - parovi surogata
Kada je u pitanju UNICODE specifikacija, postoji "rupa" / 'bermudski trougao' između kodnih pozicija 55296 (0xD800) i 57343 (0xDFFF).
Ova čudna 'tvorevina' predstavlja raspon od dve grupe po 1024 pozicije, koje se ne koriste za indeksiranje znakova, već omogućavaju da se, prostim nadovezivanjem vrednosti iz ovih grupa, adresira 2^20, odnosno, 1048576 znakova.
Na ovaj način, preko standarda UTF-16, obavlja se enkodiranje / dekodiranje kodnih pozicija većih od 65536, pri čemu:
- pozicije od 55296 do 56319 zauzimaju tzv. viši surogati (high surrogates)
- pozicije od 56320 do 57343 zauzimaju niži surogati (low surrogates)

Naarvno, pomenuti proces se ne dešava sam od sebe (i - pre svega - ne verujemo da prethodna prića može biti jasna sama po sebi), pomenuti "surogati" ne nastaju tek tako, ali, procedura je relativno jednostavna, pa ćemo je detaljno razmotriti.
Prvo je potrebno od kodne pozicije oduzeti 65536:

Surogat je 20-bitni zapis date vrednosti, pri čemu se deli na dva 10-bitna bloka, od kojih će viših 10 bitova biti 'utisnuto' u raspon viših surogata, dok će drugih 10 bitova biti 'utisnuto' u raspon nižih surogata.

Da bismo to izveli, prvih 10 bitova sabiramo sa početnom pozicijom raspona viših surogata (55296, odnosno 0xD800):

Dobijeni rezultat zapisujemo kao prvu kombinaciju od dva bajta:

Nižih 10 bitova sabiramo sa početnom pozicijom raspona nižih surogata (563200, odnosno 0xDC00):

Dobijeni rezultat zapisujemo kao drugu kombinaciju od dva bajta.

Ovim je znak formairan.
Situacija u kojoj se, pri čitanju UTF-16 znakova, vrednost iz raspona nižih surogata pojavi pre odgovarajuće vrednosti iz raspona viših surogata, ili se vrednost iz raspona viših surogata pojavi samostalno - predstavlja signal da je došlo do greške u čitanju (ovo je kontrolni mehanizam čiji je cilj da predupredi greške u prenosu znakova).
Prednosti, nedostaci, oblast upotrebe
Da bi UTF-16, kao način kodiranja znakova, bio zaista univerzalan, morala bi biti otklonjena dva nedostatka:
- UTF-16 zapis očigledno nije direktno kompatibilan sa ASCII datotekama (direktno čitanje ASCII datoteke, pri čemu bi se znakovi koji inače zauzimaju jedan bajt, čitali u blokovima od po dva bajta, dovelo bi do grešaka)
- konvertovanje ASCII datoteka u UTF-16 datoteke, duplira memorijsko zauzeće.
Pomenuti nedostaci čine UTF-16 nepraktičnim za kodiranje web stranica i trajno čuvanje teksta, ali je zato UTF-16 i dalje način zapisa znakova koji se najčešće koristi interno, u operativnim sistemima, aplikacijama i programskim jezicima (gde dodatno memorijsko zauzeće ne predstavlja preveliki problem, pa stoga UTF-16 predstavlja praktičnije rešenje od UTF-8 zapisa i starijih, pervaziđenih rešenja).
UTF-32
UTF-32 predstavlja način da se znak sa bilo kojom kodnom pozicijom zapiše neposredno, bez šifriranja / utiskivanja bitova (kao što je slučaj sa UTF-16 kodiranjem, kao i sa stanrdom UTF-8, o kome ćemo tek pisati).
Znak '🙂' (popularni smajli), čija je kodna pozicija 128578, zahteva 3 bajta za zapis ....

.... pri čemu je (čak i u ovom, najmanje "dramatičnom") slučaju, jasno da se jedan bajt uopšte ne koristi:

Po pitanju "rasipanja" prostora, stvari su joše gore kada zapisujemo uobičajenije UNICODE znakove:

.... u kom slučaju se nepotrebno koriste dva bajta ....

..... a naravno, najgora situacije je sa zapisom znakova iz ASCII specifikacije ....

.... u kom slučaju se nepotrebno koriste tri bajta:

UTF-32 (za razliku od standarda UTF-16 i UTF-8) nije toliko zastupljen, ali se često koristi u aplikacijama za zapis pojedinačnih znakova.
Kao što smo već ranije spominjali, za prenos i čuvanje većih količina teksta, najčešće se koristi prilično elegantno rešenje u vidu UTF-8 specifikacije ....
UTF-8 specifikacija
Iako, kao i ostale pomenute metode kodiranja, ni UTF-8 zapis nije bez nedostataka, upravo je ovaj standard (kao što smo već pominjali) najčešće u upotrebi kada je u pitanju zapis datoteka i kodiranje web dokumenata.
Osnovna ideja koja stoji iza UTF-8 zapisa, je da se znakovi kodiraju preko blokova od 8 bita, tako da se znakovi iz ASCII tabele (i dalje) zapisuju preko jednog bajta, a da se za ostale znakove uvode dodatni bajtovi, ali - samo po potrebi.
Da budemo precizniji: zapis prvih 128 znakova je isti kao i preko ASCII tabele, a ostali znakovi zapisuju se na nešto komplikovaniji način koji omogućava prostornu uštedu ali zahteva malo više procesorskog vremena pri čitanju i pisanju znakova.
Sve to "lepo zvuči", ali, glavno pitanje je - kako se ideja sprovodi u delo.
Primer formiranja kodnih pozicija preko jednog ili dva bajta
Znakovi iz ASCII tabele ....

.... (kao što smo rekli) i dalje se zapisuju na isti način.
Međutim - glavna informacija u smislu enkodiranja / dekodiranja znaka je (kao što verovatno i sami očekujete) - prvi bit:

- ako je prvi bit 0 - u pitanju je znak iz ASCII tabele
- ako je prvi bit 1 - u pitanju je znak sa kodnom pozicijom preko 127, koji se kodira preko (bar) dva bajta
Na gornjoj slici, prvi bajt nije uključen i upravo je to informacija UTF-8 parseru da za dekodiranje datog znaka neće biti potrebno čitanje dodatnih bajtova.
U tome leži pomenuta elegancija UTF-8 pristupa: ASCII je 7-bitni standard, ali se (kao što znamo) tipično prenosi preko osam bita, što ostavlja mogućnost da se prvi bit koristi kao prenosilac informacije - da li će za dekodiranje kodne pozicije datog znaka biti dovoljno da se pročita jedan bajt (kao u ovom slučaju), ili će biti potrebni i dodatni bajtovi.
Ako je (nasuprot prethodnom slučaju) prvi bit uključen, to će podrazumevati čitanje (bar) dva bajta:

- preko prvih nekoliko bitova u prvom bajtu, definisan je ukupan broj bajtova koji se koriste za enkodiranje znaka (posmatra se ukupan broj jedinica, posle čega mora biti zapisana nula)
- prvi dva bita u ostalim bajtovima moraju biti redom
1
i0
- preko preostalih bitova (u svim bajtovima), zapisuje se kodna pozicija
Na gornjoj slici vidimo kako se preko dva bajta, po UTF-8 specifikaciji, formira znak 'Č'.
Kada na prvoj poziciji (u prvom bajtu) pronađemo jedinicu, očitaćemo i drugi bit. Ako na datoj poziciji takođe pronađemo jedinicu, a na trećoj poziciji nulu:

.... to će značiti da je za formiranje kodne pozicije potrebno pročitati još jedan bajt (odnosno, da se za dati znak koriste ukupno dva bajta):

Drugi bajt mora počinjati kombinacijom bitova 10
, a, kada se izdvoje preostali bitovi u oba bajta ....

.... dobija se 11 bitova preko kojih možemo zapisivati znakove sa kodnim pozicijama u rasponu od 0 do 2047 (2 ^ 11 - 1).
Konkretna kombinacija bitova 100001100
, formira vrednost 268 (256 + 8 + 4), što je kodna pozicija znaka 'Č', sa kojom smo se već susretali.
Svrha kontrolnih bitova
Kodiranje drugog bajta (odnoson, ostalih bajtova, u opštem slučaju), kombinacijom bitova 10
na samom početku, deluje malo "napotrebno", ali u pitanju je kontrolni mehanizam koji je uveden zarad situacija u kojima se tekst ne prenosi u obliku datoteka, već znak-po-znak (streaming).
U takvim situacijama, početna dva bita pružaju informaciju o potencijalnim greškama koje mogu nastati u prenosu:
- ako drugi bajt počinje nulom, to je signal da znak nije pravilno enkodiran, što znači da prethodni bajt treba odbaciti (i formirati vrednost korišćenjem samo drugog bajta, koji se u tom slučaju prepoznaje kao samostalni "ASCII" znak)
- ako drugi bajt počinje sa
11
, to je takođe signal da prethodni bajt treba odbaciti, a u ovom slučaju se za formiranje vrednost formira kodne pozicije mora pročitati i sledeći bajt (koji mora počinjati kombinacijom bitova10
)
Formiranje kodne pozicije preko tri bajta, ili više bajtova
Za formiranje kodnih pozicija koje prevazilaze vrednost 2047, koristićemo tri bajta, (po istom principu - u prvom bajtu je zapisano koliko bajtova se koristi za enkodiranje / dekodiranje znaka; ostali počinju sa 10
):

Za enkodiranje je raspoloživo 16 bitova
, te je stoga maksimalna kodna pozicija koja se može zapisati na ovaj način 65535
.
Za formiranje kodnih pozicija koje prevazilaze 65535, potrebno je koristiti četiri bajta.

Za enkodiranje je raspoloživo 21 bit
, te je stoga maksimalna kodna pozicija koja se može zapisati na ovaj način 2097151
.
Teoretski, preko UTF-8 specifikacije, moguće je koristiti i pet, pa i šest bajtova (što možete isprobati u mini-aplikaciji na kraju ovog članka), ali, budući da preko četiri bajta možemo zapisati bilo koji znak čija je kodna pozicija između 65536 i 2097151, pri čemu navedena gornja granica daleko prevazilazi broj znakova koji su trenutno prisutni u UNICODE specifikaciji, tome u praktičnom smislu ne moramo pridavati preveliki značaj.
Primer čitanja poruke enkodirane po UTF-8 standardu
Da bismo još bolje utvrdili sve navedeno, razmotrićemo sledeći primer:
Tekstualna datoteka sastoji se iz sledećih bajtova: 196 140 97 197 161 97
:

.... i potrebno je pročitati poruku koja je u datoteci sadržana.
Prvi bajt ....

.... sugeriše da je za dešifrovanje znaka potrebno počitati još jedan bajt:

Preko 11 bitova, formiraćemo vrednost 268, što predstavlja znak 'Č':

Sledeći bajt, počinje nulom ....

.... što znači da odmah možemo pročitati preostalih 7 bitova, koji daju vrednost 97, što predstavlja znak 'a':

Četvrti bajt ....

.... (kao i prvi) sugeriše da je za dekodiranje znaka potrebno pročitati dva bajta (odnosno - još jedan bajt) ....

.... a preko datih 11 bitova, definisana je vrednost 353, odnosno znak 'š':

Šesti (poslednji) bajt počinje nulom ....

.... što znači da odmah možemo dekodirati znak preko preostalih 7 bitova:

Poruka sadržana u tekstualnoj datoteci je "Čaša".

Formular: UTF-8 enkoder / dekoder
Enkodiranje
Enkoder uzima vrednost iz numeričkog ulaznog polja, vraća detaljan prikaz strukture bitova enkodiranog znaka, brojčane vrednosti bajtova (u dekadnom sistemu) i ispisuje znak.
Dekodiranje
Dekoder iz ulaznog polja uzima niz bajtova koji predstavljaju (ili, ne predstavljaju?) UTF-8 poruku i, u slučaju uspešnog čitanja, ispisuje dekodiranu poruku.
Zaključak / kraka analiza
U ovom članku smo se podosta "napričali" o metodama enkodiranja / dekodiranja znakova, ali, tema za razgovor ima još ....
Iako smo najviše prostora posvetili UTF-8 standardu i implicirali da ovaj standard predstavlja najoptimalnije rešenje , UTF-8 svakako nije bez nedostataka:
- za predstavljanje znakova pojedinih pisama preko UTF-16 enkodiranja (primer: kinesko pismo), dovoljna su 2 bajta, dok je, kada se za iste znakove koristi UTF-8 enkodiranje, potrebno koristiti 3 bajta
- procedure enkodriranja i dekodiraja UTF-8 znakova su relativno komplikovane za implementaciju, pa je time i enkodiranje / dekodiranje UTF-8 znakova nešto sporije
Ako izraz "win-win" (iz engleskog jezika) shvatimo kao nešto što označava pogodbe u kojima svaka strana dobija, ili situacije u koijma sve izlazi na dobro, onda bismo situaciju sa metodama UTF enkodiranja mogli (pomalo slikovito) shvatiti kao svojevrsnu "lose-lose" situaciju.
Ni jedna od opcija nije skroz dobra, pa je na kraju potrebno biti praktičan:
- tamo gde je optimalnije koristiti UTF-16, koristi(će) se UTF-16 (isto važi i za UTF-32, koji se ipak, kao što smo već naveli, ređe koristi)
- programski jezici godinama unazad sadrže funkcije za UTF-8/16/32 enkodiranje/dekodiranje, tako da programeri koji ne žele time da se bave, ne moraju time da se bave
- savremeni računari su duži niz godina dovoljno brzi da omoguće da razlika u brzini između čitanja ASCII, ili UTF-16 datoka (sa jedne strane) i UTF-8 datoteka (sa druge), bude skoro zanemarljiva
Takođe, mogli bismo spomenuti da metode enkodiranja UTF-16, UTF-32 i UTF-8 nisu jedine postojeće (ali, svakako jesu najuobičajenije, pogotovo UTF-8), pa, ako vas tematiku predstavljanja znakova na računarima dodatno zanima, i to može biti ideja za dalje istraživanje ....