nav_dugme codeBlog codeBlog
  • početna Početna stranica
  • Sačuvani članci Sačuvani članci
  • Članci
     (spisak)
  • Kontakt
Povratak na vrh stranice

Info & povezani članci Info o članku - dugme

Info

trejler_sat Datum objave: 22.07.2021.

trejler_olovka Poslednja izmena: 20.02.2025.

trejler_dokument Jezici: ----

trejler_teg_narandzasti Težina: 8/10

ascii
unicode
fontovi
obrada teksta
web dizajn
datoteke
bitovski operatori
teorija
zanimljivosti

Povezani članci

UNIX Time - Predstavljanje datuma i vremena na računarimaOperacije sa tekstualnim datotekama u programskim jezicima C i PythonŠablonske niske u programskim jezicimaFontovi u web dizajnu (osnove tipografije)Uvod u web dizajn - 1. deo - Početni koraciCallback funkcije i lambda izraziUpotreba specijalnih znakova u HTML datotekamaKako napraviti syntax highlighterIzbor prvog programskog jezikaGNU/Linux - 1. deo - Uvod
Svi članci
On two occasions, I have been asked [by members of Parliament], 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out?' I am not able to rightly apprehend the kind of confusion of ideas that could provoke such a question.
Charles Babbage

ASCII, UNICODE i UTF - Predstavljanje znakova na računarima

Facebook LinkedIn Twitter Viber WhatsApp E-mail
zoom_plus zoom_minus bookmark
početna > Članci > Zanimljivosti

Uvod

Everyone in the world should be able to use their own language on phones and computers.

Citat koji ste prethodno pročitali, preuzet je sa zvaničnog sajta konzorcijuma UNICODE i potcrtava osnovnu ideju koja stoji iza pomenutog standarda, koji (baš kao što je navedeno), godinama unazad omogućava korisnicima najrazličitijih računara, operativnih sistema i korisničkih programa, da koriste na svojim uređajima maternji jezik (uz odgovarajuće pismo), ili bilo koji drugi jezik.

Sa jedne strane, reklo bi se da 'nekako jeste red' da početkom treće decenije dvadesetog veka bude tako kako je navedeno, ali, situacija nije oduvek bila povoljna.

Nekada su "nad mutnom vodom graktale vrane" .....

Zapis znakova na računarima

(Osnovni principi)

Pre nego što je postalo moguće na računarima koristiti "sve znakove iz bilo kog jezika", * na red su prvo došli znakovi engleskog alfabeta, uz cifre, znakove interpunkcije, znakove osnovnih matematičkih operacija i određeni broj drugih uobičajenijih znakova.

Međutim, bilo je potrebno uspostaviti, pre svega, osnovni sistem koji uopšte omogućava bilo kakvo korišćenje znakova na računarima.

Da bismo vam malčice "zakomplikovali život" (zapravo, da bismo vam pomogli da što bolje razumete tematiku članka :)), pre nego što pređemo na ASCII i UNICODE - osvrnućemo se na osnovni princip zapisivanja znakova na računarima (a nešto kasnije takođe ćemo se osvrnuti i na vrane). :)

* Standard UNICODE ne 'pokriva' doslovno sve znakove, ali, broj kodiranih znakova meri se desetinama hiljada i obuhvata sva iole poznatija i češće korišćena pisma (kao i mnoga pisma iz prošlih vekova, razne specijalne znakove i sl).

Kako računari (uopšte) mogu razumeti znakove?

U članku u kome smo diskutovali o tome zašto binarni brojevni sistem (a ne dekadni), predstavlja matematičku osnovu računarskih sistema, objasnili smo da računari, ne samo da nisu u stanju da neposredno razumeju dekadni brojevni sistem, već - nisu u stanju da neposredno razumeju brojeve ("ikako").

Odnosno: računari su u stanju da 'razumeju' samo određena naponska stanja u elektronskim kolima.

Iz prethodno navedenog može se zaključiti da računari, koji nisu u stanju da neposredno razumeju (čak ni binarne) brojeve, mogu samo imati još većih poteškoća pri pokušaju da neposredno 'razumeju' slova i druge znakove (kojih ima znatno više od cifara koje su u upotrebi u uobičajenim brojevnim sistemima).

Međutim (u praktičnom smislu), ukoliko su logička kola u računarima u stanju da prepoznaju dva različita naponska stanja: "nema napona" i "ima napona" (a kao što je poznato, logička kola u računarima jesu sposobna za takvo raspoznavanje), navedena naponska stanja se mogu shvatiti i kao cifre binarnog brojevnog sistema (0 i 1), nule i jedinice se dalje mogu nizati tako da tvore binarne brojeve, koji (kasnije/'ako zatreba') mogu biti interpretirani, tako da korisnicima budu prikazani kao dekadni brojevi.

Nizanjem bitova (ili, da budemo precizniji i praktičniji - nizanjem bajtova), takođe se mogu kodirati i znakovi.

Osnovna ideja za kodiranje znakova (makar u okviru jednog računarskog sistema), podrazumeva da se svaki znak povezuje sa unapred izabranom brojčanom vrednošću (uvek istom), a kada se navedena ideja uspešno implementira u okviru jednog računarskog sistema, ostaje "samo" pitanje - kako uskladiti više različitih računarskih sistema.

Što se tiče "vrana" ....

U današnje vreme, svet se može posmatrati kao "globalno selo" u kome postoji mrežna infrastruktura koja omogućava da se veza između računara u Srbiji i Novom Zelandu rutinski uspostavi za manje od jedne sekunde (ponekad i za manje od pola sekunde (!)), i stoga nije lako zamisliti nekadašnji svet, u kome su računari bili malobrojni i nisu bili u stanju da razmenjuju ni osnovne tekstualne poruke.

Dali smo sebi izvesnu "pesničku slobodu" u uvodu, sa (parafraziranim) citatom koji će nešto stariji čitaoci prepoznati kao deo jednog od uvodnih poglavlja sjajnog romana Na Drini ćuprija, tj. scenu u kojoj mosta - koji je praktično pokrenuo život naselja u kome je nekoliko godina kasnije podignut - još uvek nema (putnike preko reke prevozi trošna skela, iznad mutne vode grakću vrane, obrisi novog vremena još nisu ocrtani, ali .... stvari počinju polako da se odvijaju).

Ako smo za vaš ukus previše 'rastegli' poređenje (ili ako ste suviše mladi da uopšte možete razumeti na šta smo mislili :)), samo nastavite sa čitanjem i nemojte nam zameriti što smo vam oduzeli nekoliko desetina sekundi. U suprotnom, verujemo da ste tačno prepoznali na šta smo 'ciljali', jer nekada je i svet računarskih tehnologija bio 'bez mostova' (koji još nisu bili izgrađeni, i koji ne nastaju "sami od sebe" i "tek tako").

U prvim godinama razvoja računarske industrije (druga polovina 50-ih godina 20. veka i veći deo 60-ih godina), odnosno, pre uvođenja ASCII standarda, zapis znakova na različitim računarskim sistemima - nije bio usklađen.

Različite, raznolike i udaljene računare, odlikovali su idiosinkratični sistemi za zapis znakova (idiosinkratičan = sebi svojstven), i stoga - reklo bi se krajnje očekivano - nije postojala ni mogućnost razmene tekstualnih poruka.

U navedenom periodu, dok su računari još uvek delovali kao uređaji iz domena naučne fantastike (makar u kontekstu šire primene), nemogućnost međusobne komunikacije računara nije predstavljala preveliki problem (recimo da je donekle tako), ali, razmišljalo se i o budućnosti, za koju se još onomad očekivalo da će podrazumevati širu rasprostranjenost računara i veći obim komunikacije između računara, i zaključeno je da takva budućnost neće biti moguća bez (pre svega), opšteprihvaćenog standarda za razmenu tekstualnih poruka između različitih računarskih sistema.

Pojava ASCII standarda i osnovne smernice

American Standard Code for Information Interchange (skraćeno - ASCII), * prvi je široko rasprostranjen i opšteprihvaćen standard za kodiranje znakova u elektronskoj komunikaciji, i (kao takav), podržan je na većini računarskih i telekomunikacionih sistema koji su se u međuvremenu pojavili.

Prva specifikacija ASCII standarda objavljena je 1963, međutim, standard nije prihvaćen odmah, već je tokom sledećih nekoliko godina postepeno poprimao oblik koji poznajemo danas, a u upotrebu je praktično ušao krajem šezdesetih godina.

U osnovnom tehničkom smislu, ASCII standard podrazumeva da se brojevi u rasponu od 0 do 127 koriste za kodiranje: velikih i malih slova engleskog alfabeta, ** cifara i drugih pažljivo biranih specijalnih znakova.

* Skraćenica se čita kao "as-ki" i označava "Američki standardni kod za razmenu informacija".

** ASCII standard prilagođen je engleskom govornom području, budući da je većina kompanija koje stoje iza ranih koraka u računarskoj industriji (i iza ASCII tabele, tj. standarda), upravo sa engleskog govornog područja (uglavnom SAD), a ne može se baš reći ni to da je u početku uopšte bilo previše brige oko proširivanja kapaciteta (tj. obuhvatanja drugih jezika i pisama).

Kosmopolitske ideje o prilagođavanju operativnih sistema i drugog softvera ostalim jezicima ('koji nisu engleski'), došle su tek kasnije ....

ASCII

ASCII tabela sadrži 128 znakova (koje možete videti u donjem formularu) i formatirana je tako da prve 32 pozicije zauzimaju 'kontrolni znakovi' (to jest, znakovi koji se ne vide u štampi ili na ekranu, već imaju posebnu funkciju u različitim računarskim sistemima), 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), izdvojićemo nekoliko uobičajenijih (sa dekadnim kodovima, za lakše snalaženje):

  • 8 - Backspace (taster BACKSPACE)
  • 13 - Carriage return (taster "ENTER")
  • 27 - Escape (taster ESC)
  • 32 - Space (razmak na tastaturi)
dec
hex
bin
simbol / opis
Forma 1. - ASCII tabela.

(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 po pitanju pozicija slova i cifara: tabela treba da bude udešena tako da se cifra 1, kao i veliko i malo slovo 'A' - "poklope sa jedinicom".

Navedena ideja je zanimljiva, ali i pomalo čudna na prvi pogled, i stoga ćemo pojasniti o čemu se radi ....

Kao prvo, očigledno je da poziciju #1 u ASCII tabeli (ili bilo koju drugu poziciju), ne mogu zauzimati tri različita znaka istovremeno, vidimo i to da nijedan od tri navedena znaka nije na prvoj poziciji u tabeli, i (takođe) - ne deluje na prvi pogled da znakovi '0', 'A' i 'a' imaju previše veze sa kodnim vrednostima 48, 65 i 97 (sa kojima su povezani).

Ipak, uz pažljivije sagledavanje binarnih vrednosti koje su pripisane ciframa i slovima, moguće je zapaziti red i pravilnosti.

Ako posmatramo zapis cifara preko ASCII tabele (uzećemo samo nekoliko prvih cifara za primer) ....

ASCII 01
Slika 1. - Zapis nekoliko prvih cifara po ASCII standardu.

.... može se zapaziti da bitovi na najnižim pozicijama odgovaraju vrednostima cifara (pri čemu su uključeni i bitovi na pozicijama 32 i 16, što daje zbir 48):

  • cifra '0' ima ASCII kod 48, što se može shvatiti kao 48 + 0
  • cifra '1' ima ASCII kod 49, što se može shvatiti kao 48 + 1
  • cifra '2' ima ASCII kod 50, što se može shvatiti kao 48 + 2

Ista ideja stoji i iza zapisa velikih slova:

ASCII 02
Slika 2. - Zapis nekoliko prvih velikih slova engleskog alfabeta po ASCII standardu.

.... gde se takođe može zapaziti da bitovi na najnižim pozicijama odgovaraju pozicijama znakova u engleskom alfabetu ....

  • znak 'A' ima ASCII kod 65, što se može shvatiti kao 64 + 1
  • znak 'B' ima ASCII kod 66, što se može shvatiti kao 64 + 2
  • znak 'C' ima ASCII kod 67, što se može shvatiti kao 64 + 3

Mala slova takođe se kodiraju po sličnom principu:

ASCII 03
Slika 3. - Zapis nekoliko prvih malih slova engleskog alfabeta po ASCII standardu.

Bitovi na najnižim pozicijama (ponovo) odgovaraju pozicijama znakova u engleskom alfabetu, i (takođe), kodne vrednosti su veće za 32 u odnosu na velika slova:

  • znak 'a' ima ASCII kod 97, što se može shvatiti kao 64 + 32 + 1
  • znak 'b' ima ASCII kod 98, što se može shvatiti kao 64 + 32 + 2
  • znak 'c' ima ASCII kod 99, što se može shvatiti kao 64 + 32 + 3

Poznavanje navedenih pravilnosti, može dobro poslužiti pri pisanju programa.

Manipulacija bitovima i drugi programski kodovi za ispis znakova

Uz upotrebu bitovskih operatora (pod uslovom da smo sigurni da znak jeste "ono što bi trebalo da bude"), velika slova se vrlo lako mogu pretvarati u mala slova, mala slova se mogu pretvarati u velika slova, znakovi koji predstavljaju cifre mogu se pretvarati u odgovarajuće celobrojne vrednosti i sl.

Na primer:

		
malo_slovo   = veliko_slovo   |  32;  // 'A' => 'a'
veliko_slovo = malo_slovo     & ~32;  // 'a' => 'A'
cifra        = znak_za_cifru  & 15;   // '1' => 1
		
	
Slika 4. - Programski kod za manipulaciju bitovima (pretvaranje velikih slova u mala, pretvaranje malih slova u velika, pretvaranje znakova za cifre u odgovarajuće celobrojne vrednosti).

Kad smo već kod programskih kodova, u C-u je (takođe) vrlo jednostavno dobiti ispis kodne vrednosti znaka:

		
char c = 'A';

printf("%c\n", c); // A
printf("%d\n", c); // 65
		
	
Slika 5. - Ispis ASCII vrednosti znaka, u programskom jeziku C.

Pomenimo da se navedene operacije mogu izvesti i preko JavaScript-a * (pri čemu ima i dodatnih mogućnosti):

		
let c = 65;

console.log(`&#c;`);         // A
console.log(c.toString(2));  // 01000001
console.log(c.toString(16)); // 41
console.log(c);              // 65
		
	
Slika 6. - Ispis binarnog, dekadnog i heksadekadnog ASCII koda znaka, preko ugrađenih funkcija u jeziku JavaScript.

Naravno, slični zahvati mogući su i u većini drugih popularnih jezika.

* Ako se pitate zašto smo "izdvojili" JavaScript, jednostavno je: za razliku od drugih programskih jezika, primere iz JavaScript-a možete (po želji) isprobati odmah u browseru (u kome trenutno čitate članak). :)

Proširene ASCII tabele / kodne stranice

ASCII tabela je sedmobitna (u smislu: bilo koji pojedinačni znak iz ASCII tabele, može se definisati preko sedam bita), međutim - u praksi - pojedinačni ASCII znakovi se zapisuju korišćenjem celih bajtova (tj. preko osam bita), i stoga je jasno da u takvom zapisu ima mesta za dodatnih 128 znakova.

U periodu posle početnog 'uhodavanja' sa ASCII standardom, a pogotovo između kraja sedamdesetih i sredine devedesetih godina dvadesetog veka, pojavile su se brojne 'varijacije na temu' ASCII tabele.

U navedenom kontekstu, termin 'kodna stranica' (eng. code page), odnosi se na konkretnu 'proširenu ASCII tabelu' (koja se koristi u određenom računarskom sistemu).

U okviru različitih kodnih stranica, pozicije iznad 127 korišćene su za: dodavanje podrške za specijalne znakove opšteg tipa, ili, za definisanje znakova različitih svetskih pisama.

Osim dodavanja znakova na pozicije 'preko 127', u određenim kodnim stranicama bilo je i toga da se poneki znak iz standardne ASCII specifikacije (tj. znak sa prvih 128 pozicija) - zameni nekim drugim znakom, koji je smatran praktičnijim (određeni znakovi, koji su na početku imali posebnu namenu, do poslednje četvrtine 20. veka su već praktično izašli iz upotrebe).

Kodna stranica 437

Uzmimo kao prvi primer (iz razloga nekadašnje velike popularnosti), kodnu stranicu 437, izmenjenu i proširenu ASCII tabelu koja je uvedena sa prvobitnim PC računarima, odnosno sa operativnim sistemom DOS (a korišćena je i u ranim verzijama Windows-a):

		
199 - ╟

200 - ╚

201 - ╔

195 - ├

192 - └

218 - ┌

30 - ▲

31 - ▼
		
	
Slika 7. - Izvod iz kodne stranice 437.

Kodna stranica 437 nije smišljena sa ciljem da pruži podršku za znakove iz "ne-anglosaksonskih" pisama, već - da omogući prikaz dodatnih specijalnih znakova, pre svega onih koji su korišćeni za iscrtavanje prozora u okviru tekstualnog okruženja (verujemo da programeri sa podužim stažom nisu zaboravili vremena kada su znakovi sa gornje slike bili korišćeni za kreiranje prozora u DOS programima). *

Međutim, u poslednjim godinama pre nego što je standard UNICODE praktično 'istisnuo' kodne stranice iz upotrebe, ** pojam "kodna stranica" se tipično vezivao za proširene ASCII tabele sa podrškom za različita pisma, i stoga, pre nego što konačno pređemo na UNICODE i formate za kodiranje znakova (pre svega UTF-8, ali i druge), napravićemo kratak pregled nekada popularnih kodnih stranica sa podrškom za ćirilične i latinične znakove. ***

* Osim u malobrojnim i vrlo specifičnim okolnostima, operativni sistem DOS se ne koristi više (poslednjih ~dvadesetak godina), ali, TUI aplikacije su zapravo i dalje "žive i zdrave", pogotovo na Linux-u i drugim UNIX-olikim operativnim sistemima (TUI = Terminal User Interface: korisnički interfejs koji je sačinjen od specijalnih znakova koji praktično "simuliraju" prozore i druge grafičke elemente).

** Kodne stranice nisu doslovno 'istisnute iz upotrebe'; ima ih (još uvek) 'ponegde', ali, znatno manje nego pre 20+ godina.

*** Kodne stranice sa podrškom za različita pisma, možemo smatrati 'prethodnicama' standarda UNICODE.

Kodna stranica Windows-1251 (ćirilica)

Kodna stranica 1251 (koja je ranije bila korišćena na Windows-u), odgovara znakovima srpskog ćiriličnog pisma (zarad preglednosti, navešćemo samo nekoliko znakova) ....

		
230 - ж
158 - ћ
247 - ч
248 - ш
		
	
Slika 8. - Izvod iz kodne stranice Windows-1251 (koja sadrži znake ćirilice).

Kodna stranica Windows-1250 (latinica)

Za prikaz latiničnih znakova iz slovenskih jezika (na Windows-u), bila je zadužena kodna stranica 1250:

		
232 - č
230 - ć
154 - š
158 - ž
		
	
Slika 9. - Izvod iz kodne stranice Windows-1250 (koja sadrži znake latinice).

Vidimo da kodovi znakova ćirilice i latinice nisu proporcionalni poziciji znakova u navedenim pismima, kao i to da među pozicijama istovetnih znakova u kodnim rasporedima 1251 i 1250, nema poklapanja (primer: znakovi "ч" i "č").

Kodna stranica 737 (grčki alfabet)

Da bismo dodatno ilustrovali (relativnu) * proizvoljnost pri razmeštanju znakova u kodnim stranicama, uzećemo za primer još i Kodnu Stranicu 737, preko koje su u DOS-u bila definisana grčka slova (prikazaćemo nekoliko pozicija koje smo već navodili) ....

		
154 - γ
158 - η
230 - ό
232 - ϋ
		
	
Slika 10. - Izvod iz kodne stranice 737 (koja sadrži znakove grčkog alfabeta).

* Konstatacija se najviše odnosi na pozicije 128+ (niže pozicije uglavnom su se poklapale sa standardnom ASCII tabelom).

Dovoljno je pogledati prethodne primere i doći do zaključka da kodne stranice deluju pomalo neorganizovano (bar iz današnje perspektive), a jasno je i to da bilo kakva greška u smislu 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 pisama, dok, ako pomešamo (na primer) ćirilicu i grčko pismo - nećemo biti "takve sreće").

U svemu što smo do sada pominjali i što ćemo tek pominjati (napomena nije vezana samo za ASCII i kodne stranice, već, pogotovo za UNICODE), veoma je bitno da li određeni font koji je potrebno koristiti, podržava (ili ne podržava) određeni znak, to jest, da li je unutar fonta definisana vektorska slika (eng. glyph), koja zapravo omogućava prikaz datog znaka.

Recimo, ukoliko se na web stranici koristi japansko ili kinesko pismo, pri čemu je eksplicitno navedeno da treba (za prikaz teksta) koristiti određeni font - a navedeni font pri tom ne podržava znakove koje treba prikazati - doći će do greške u prikazu teksta.

(Nismo uzimali za primer evropska pisma, jer ih većina uobičajenih fontova podržava.)

Tekst može biti korektno prikazan samo ukoliko fontovi koji se navode - podržavaju znakove koje je potrebno prikazati.

Naravno, može se 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 sagleda i izgradi kako dolikuje.

U svakom slučaju, do sada opisana situacija može se rezimirati na sledeći način:

  • ASCII tabela nudi razuman raspored znakova i podršku za engleski alfabet, ali - ne postoji podrška za znakove ostalih pisama (niti podrška za dodatne specijalne znakove)
  • kodne stranice su (u praktičnom smislu), suviše neorganizovane

.... i može se (iz svega navedenog) jasno zaključiti da je bilo potrebno iznaći praktičnije rešenje.

UNICODE

UNICODE je (sveprisutni i opšteprihvaćeni) standard za kodiranje znakova u računarskim sistemima, iza koga stoji nekoliko osnovnih ideja:

  • glavni cilj je - obuhvatiti sve znakove, iz svih svetskih pisama (odnosno - koliko god je moguće znakova)
  • svaki znak mora imati jedinstvenu kodnu poziciju (eng. code point) - što je pristup koji je idejno sličan ASCII standardu
  • UNICODE specifikacija mora biti potpuno kompatibilna sa ASCII specifikacijom (kodovi znakova iz ASCII tabele odgovaraju kodnim pozicijama iz UNICODE specifikacije)

Termin UNICODE zapravo nije skraćenica, već reč koja označava prirodu standarda u okviru koga su znakovi definisani na jedinstven (eng. "UNIque"), objedinjen ("UNIfied") i univerzalan ("UNIversal") način.

Konzorcijum UNICODE osnovan je krajem osamdesetih godina dvadesetog veka, osnivači 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 oblasti obrade teksta na računarima).

U početku, specifikacija je obuhvatala nekoliko desetina hiljada znakova (što svakako nije mali broj), ali, već do početka 21. veka, prevaziđen je broj od 100 hiljada znakova - što je zahtevalo 'prepravljanje' tehničkih rešenja za enkodiranje znakova.

Tačan broj znakova koji su uvršteni u UNICODE specifikaciju (do trenutka objavljivanja ovog članka), iznosi: 143859.

U kontekstu 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 format UTF-8 (o svemu navedenom pisaćemo detaljnije u nastavku).

Enkodiranje UNICODE znakova

U okviru standarda UNICODE, znakovi se kodiraju prema dogovoru, tako da svakom znaku odgovara jedinstvena 'kodna pozicija' (eng. code point), čime je otklonjena zbrka koju je (ranije) unosilo korišćenje različitih kodnih stranica:

  • prvih 128 pozicija * zauzimaju redom znakovi iz ASCII tabele
  • slede zatim uobičajenija pisma evropskih jezika, sa znakovima koji zauzimaju kodne pozicije relativno blizu početnih ASCII pozicija (na primer: latinica (tj. manje uobičajeni znakovi latiničnih pisama), ćirilica, grčki i ruski alfabet, i sl)
  • više pozicije zauzimaju manje uobičajena (ali i dalje široko rasprostranjena) pisma sa velikim brojem znakova (kinesko, japansko, korejsko i sl)
  • najviše/najudaljenije pozicije, zauzimaju najrazličitije vrste specijalnih znakova (znakovi muzičke notacije, emotikoni i sl)

Znakovi su podeljeni u tzv. "višejezične ravni" (eng. multilingual plane).

Osnovna multijezična ravan obuhvata prvih 65536 znakova (tj. 216 znakova, odnosno znakove u rasponu od 0x0000 do 0xFFFF), koji su podeljeni u sledeće grupe: "ASCII znakovi", latinica, ćirilica, znakovi "CJK" pisama (kinesko, japansko, korejsko), a prisutni su i razni simboli među kojima su znakovi valuta i sl.

"Iznad" osnove multijezične ravni nalaze se "suplementarne" multijezične ravni (koje obuhvataju (npr) emotikone i razne druge specijalne znakove).

* Kodna pozicija se može shvatiti kao jedinstvena identifikaciona oznaka određenog znaka.

Sledeće pitanje je: kako (zapravo) kodirati kodne pozicije?

ASCII znakovi zauzimaju 1 bajt (tačnije, 7 bita; manje od jednog celog bajta), dok, sa UNICODE znakovima (kojih ima mnogo više od 27), to nije i ne može biti slučaj.

Na primer, sledeći znakovi ("različite udaljenosti od ASCII pozicija") ....

		
Č  - 268
∑  - 8721
✅ - 9989
🙂 - 128578

		
	
Slika 11. - Primer nekoliko znakova čije kodne pozicije prevazilaze vrednost 127.

.... očigledno zahtevaju (shodno svojim kodnim pozicijama), više od jednog bajta za zapis (dva, tri, ili četiri).

UNICODE Transformation Format

Kao prvobitno rešenje za enkodirnje znakova, pojavio se standard UCS-2 ("Universal Coded Character Set"), koji je podrazumevao kodiranje svakog znaka preko dva bajta.

U poslednjoj deceniji 20. veka, u vreme dok je ukupan broj kodnih pozicija bio manji od 216 (65536), format UCS-2 bio je sasvim adekvatan, ali, nadomak 21. veka - broj kodnih pozicija počeo je da raste ....

Kada je broj kodnih pozicija prevazišao smeštajni kapacitet 16-bitnih promenljivih, uveden je standard UTF-16 (unapređenje standarda UCS-2), a potom su uvedeni i standardi UTF-32 i UTF-8.

U nastavku ćemo posvetiti pažnju tehničkim detaljima navedenih metoda za kodiranje znakova, prednostima i nedostacima različitih metoda, kao i oblastima primene.

Najviše pažnje posvetićemo formatu UTF-8 (pred kraj), ali, prvo ćemo predstaviti formate UTF-16 i UTF-32 (koji su se pojavili pre formata UTF-8).

UTF-16

Format UTF-16 (kao jedan od mogućih formata za kodiranje UNICODE znakova), predstavlja unapređenje formata UCS-2, * uz očuvanje osnovne ideje da se za zapis znakova koriste blokovi od 16 bita.

Početna pretpostavka da će (za)uvek biti dovoljno koristiti 216 znakova za zapis svih pojedinačnih UNICODE znakova, odavno je opovrgnuta (što smo već nagovestili), a takođe je jasno i to da se preko jednog bloka od 16 bita ne mogu kodirati brojevi veći od 216.

Shodno navedenom, jedino praktično rešenje svodi se na uvođenje dodatnog 16-bitnog bloka (po potrebi), uz korišćenje posebnog (i 'ne baš skroz jednostavnog') postupka, na koji ćemo se osvrnuti u nastavku.

* Standard UCS-2 pominjemo iz "obrazovno-istorijskih" razloga:

  • ideja koja stoji iza standarda UCS-2 je jednostavna - koristiti dva bajta za svaki znak (a neko vreme takva ideja bila je i praktična)
  • UCS-2 predstavlja osnovu standarda UTF-16 o kome diskutujemo u nastavku.

Krenućemo 'po redu', i razmotrićemo prvo situacije u kojima nije potrebno uvođenje dodatnih bajtova ....

Kada su u pitanju niže kodne pozicije, zapis znaka preko formata UTF-16 (baš kao i u slučaju starog standarda UCS-2), obavlja se uz korišćenje dva bajta.

Primera radi, znak 'Č' koji smo već pominjali (kodna pozicija 268), može se kodirati na sledeći način:

UTF-16 01
Slika 12. - Zapis znaka 'Č' preko formata UTF-16.

Za znak čija je kodna pozicija veća od 127 i istovremeno manja od 65536, korišćenje dva bajta predstavlja racionalan i optimalan izbor.

Ako se format UTF-16 primeni za kodiranje znaka 'A', čija je kodna pozicija ("i dalje") 65 ....

UTF-16 02
Slika 13. - Zapis znaka 'A' preko formata UTF-16.

.... vidimo da je zapis moguć (naravno), ali, takođe vidimo da zapis "ASCII znakova" preko formata UTF-16, praktično dovodi do dupliranja memorijskog zauzeća (reklo bi se - sasvim nepotrebno):

UTF-16 03
Slika 14. - U zapisu znaka 'A' preko formata UTF-16, prvi bajt je zauzet, iako se ne koristi (budući da je sama vrednost i dalje manja od 27.

Na slici vidimo da prvi bajt ne igra (praktično) nikakvu ulogu.

Iako UTF-16 dozvoljava korišćenje dodatne grupe od dva bajta (po potrebi), nije moguće selektivno koristiti samo jedan bajt za znakove sa prvih 128 pozicija (koje, same po sebi, ne zahtevaju dodatne bitove).

Pošto smo se osvrnuli na znakove koji se mogu kodirati preko jednog 16-bitnog bloka, vraćamo se na diskusiju o kodnim pozicijama sa kojima to nije slučaj ....

Zapis kodnih pozicija iznad 65535 (parovi surogata)

U okviru UNICODE specifikacije, postoji svojevrsna "rupa" ('bermudski trougao'), između kodnih vrednosti 55296 (0xD800) i 57343 (0xDFFF).

Navedeni raspon ne koristi se za direktno kodiranje znakova, već, za kodiranje znakova sa kodnom pozicijom koja je veća ili jednaka 65536 - po posebnom postupku.

Sam raspon kodnih vrednosti od 55296 do 57343, podeljen je na dve grupe tzv. "surogata":

  • pozicije od 55296 do 56319 zauzimaju viši surogati (eng. high surrogates)
  • pozicije od 56320 do 57343 zauzimaju niži surogati (eng. low surrogates)
UTF-16 04
Slika 15. - Raspon kodnih pozicija između 55296 i 57343 (viši i niži 'surogati'), preko kojih se kodiraju UNICODE pozicije iznad 65536.

Oba raspona sadrže po 1024 vrednosti (1010), a prostim nadovezivanjem * dve desetobitne vrednosti, može se dobiti jedna dvadesetobitna vrednost, što omogućava kodiranje znakova sve do kodne pozicije 1048576 (1020 = 1048576).

Kao što smo ranije nagovestili, ceo postupak podrazumeva (naravno), korišćenje dva uzastopna 16-bitna bloka.

* Nije teško u mislima podeliti dvadesetobitni zapis broja na levu i desnu polovinu, niti je teško spojiti dve desetobitne vrednosti u jednu dvadesetobitnu, međutim - u praksi - enkodiranje ili dekodiranje visokih UNICODE pozicija uz korišćenje formata UTF-16 - nije trivijalan postupak (ali, bez brige, nije ni previše komplikovano). :)

Proces podrazumeva "utiskivanje" prvih deset bitova u 16-bitnu vrednost iz raspona viših surogata, i (takođe), utiskivanje preostalih deset bitova u 16-bitnu vrednost iz raspona nižih surogata.

Sledi opis postupka ....

Kada program koji obavlja dekodiranje po standardu UTF-16, naiđe na 16-bitni blok iz raspona viših surogata (55296-56319), pojava navedenog bloka tumači se kao informacija koja se tiče toga da je za pravilno dekodiranje znaka potrebno pročitati još jedan 16-bitni blok (za koji se očekuje da mora pripadati rasponu nižih surogata, 56320 - 57343) *

Kodna pozicija se formira spajanjem dve grupe od deset bitova, koje se 'izvlače' iz dve uzastopne 16-bitne vrednosti iz raspona surogata.

* Bez kodiranja koje opisujemo (ili neke druge, slične metode), ne bi bilo moguće razlikovati 16-bitne blokove koje treba čitati direktno, od onih koje treba spajati sa sledećom 16-bitnom vrednošću.

Prvo ćemo prikazati primer kodiranja znaka ("da bismo uopšte imali šta da čitamo"), pri čemu ćemo zapisati kodnu poziciju 128578 (osnovni "smajli").

Za početak, potrebno je oduzeti vrednost 65536 (216), od broja koji predstavlja kodnu poziciju znaka:

UTF-16 05
Slika 16. - Kreiranje UTF-16 zapisa uz korišćenje vrednosti iz raspona viših i nižih surogata - korak 1.

Posle oduzimanja, 20-bitni zapis dobijene vrednosti (63042), deli se na dva 10-bitna bloka (kao što smo već nagovestili), posle čega se viših 10 bitova 'utiskuje' u raspon viših surogata, dok se preostalih 10 bitova 'utiskuje' u raspon nižih surogata.

UTF-16 06
Slika 17. - Kreiranje UTF-16 zapisa uz korišćenje vrednosti iz raspona viših i nižih surogata - korak 2.

Da bi 10 viših (tj. 'levih') bitova, bilo 'utisnuto' u raspon viših surogata, potrebno je sabrati prikazanu desetobitnu vrednost (111101), sa početnom pozicijom raspona viših surogata (55296, odnosno 0xD800):

UTF-16 07
Slika 18. - Kreiranje UTF-16 zapisa uz korišćenje vrednosti iz raspona viših i nižih surogata - korak 3.

Nakon sabiranja, dobijeni rezultat (55357) - zapisuje se u prvi 16-bitni blok:

UTF-16 08
Slika 19. - Kreiranje UTF-16 zapisa uz korišćenje vrednosti iz raspona viših i nižih surogata - korak 4.

Nižih (tj. 'desnih') 10 bitova (1001000010), sabira se sa početnom pozicijom raspona nižih surogata (563200, odnosno 0xDC00):

UTF-16 09
Slika 20. - Kreiranje UTF-16 zapisa uz korišćenje vrednosti iz raspona viših i nižih surogata - korak 5.

.... a dobijeni rezultat (56898), zapisuje se kao druga kombinacija od dva bajta:

UTF-16 10
Slika 21. - Kreiranje UTF-16 zapisa uz korišćenje vrednosti iz raspona viših i nižih surogata - korak 6.

Znak je sada kodiran.

Pri čitanju, potrebno je proći kroz sledeće korake (smatramo da je uspešno prepoznato da dve uzastopne 16-bitne vrednosti pripadaju odgovarajućim rasponima surogata, i prolazi se kroz 'obrnuti postupak'):

  • od prve 16-bitne vrednosti oduzima se 0xD800 (u binarnom zapisu, praktično se isključuju svi bitovi, osim onih na 10 najnižih pozicija) *
  • od druge 16-bitne vrednosti oduzima se 0xDC00 (i u ovom slučaju praktično ostaju samo bitovi na 10 najnižih pozicija) *
  • bitovi u prvoj grupi pomeraju se za deset mesta ulevo, spajaju se sa bitovima iz druge grupe (preko pomoćne 32-bitne promenljive), a potom se rezultat uvećava za 65536 **

* U praksi, umesto oduzimanja u prva dva koraka, mogu se koristiti bitovski operatori (zarad isključivanja bitova na svim pozicijama - osim na deset najnižih).

** U pitanju je 'vraćanje pozajmice' iz prethodnog koraka (kada je, u procesu enkodiranja, od vrednosti kodne pozicije prvo oduzeta vrednost 65536).

		
nizi   = nizi & 1023; // nizi & 0000001111111111
visi   = visi & 1023; // visi & 0000001111111111

int cp = (visi << 10) | nizi + 65536;
		
	
Slika 22. - Deo programskog koda za formiranje kodne pozicije koja je veća od 65536, preko formata UTF-16.

Provera

Za razliku od gornjeg primera, u kome smo samo pretpostavili da je redosled 16-bitnih blokova ispravan, u praksi se podaci moraju proveravati.

Provera se obavlja prema sledećim pravilima:

  • 16-bitni blok koji ne pripada rasponu surogata, tumači se kao zaseban znak
  • pojava 16-bitnog bloka iz raspona viših surogata, podrazumeva čitanje sledećeg bloka, pri čemu se očekuje da "sledeći" blok pripada rasponu nižih surogata (kao što smo ranije naveli)
  • sledeće okolnosti tumače se kao 'signal' da je došlo do greške:
    • 16-bitni blok sa vrednošću iz raspona nižih surogata, pojavljuje se pre odgovarajuće vrednosti iz raspona viših surogata
    • 16-bitni blok sa vrednošću iz raspona viših surogata, pojavljuje se posle 16-bitnog bloka koji takođe sadrži vrednost iz raspona viših surogata
    • pojedinačna vrednost iz raspona viših ili nižih surogata - pojavljuje se samostalno

Prednosti, nedostaci, oblast upotrebe

Da bi UTF-16 (kao način za kodiranje znakova), bio zaista univerzalan, morala bi biti otklonjena dva nedostatka:

  • zapis UTF-16 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)
  • konvertovanjem ASCII datoteka u UTF-16 datoteke, duplira se memorijsko zauzeće

Pomenuti nedostaci čine format UTF-16 nepraktičnim za kodiranje web stranica i trajno čuvanje teksta, ali, UTF-16 se i dalje koristi kao interni format za zapis znakova u operativnim sistemima i programskim jezicima (što su situacije u kojima dodatno memorijsko zauzeće ne predstavlja preveliki problem, pa stoga UTF-16 predstavlja praktičnije rešenje od formata UTF-8 i starijih, prevaziđenih rešenja).

Napomena: u praksi, postupci o kojima pišemo podrazumevaju i vođenje računa o dodatnim tehničkim detaljima (na primer, redosled bajtova u 16-bitnim i 32-bitnim blokovima (big endian/little endian), i sl), međutim, odlučili smo da određene pojedinosti ipak izostavimo iz članka (zarad očuvanja preglednosti).

UTF-32

Format za kodiranje UTF-32, predstavlja (baš kao što broj u nazivu sugeriše), 32-bitni format koji omogućava neposredno zapisivanje znakova - bez 'utiskivanja bitova' ili drugih metoda za 'šifriranje' (nasuprot formatu UTF-16, ili formatu UTF-8, o kome ćemo tek pisati).

Međutim, iako 32-bitni format (232 = 4294967296), nedvosmisleno omogućava da se obuhvati celokupan raspon UNICODE znakova - zapis sam po sebi nije optimalan.

U najpraktičnijem smislu, memorijsko zauzeće je preveliko.

Ako kao prvi primer ponovo uzmemo znak '🙂' (popularni smajli), čija kodna pozicija 128578 "prirodno" zahteva 3 bajta za zapis ....

UTF-32 01
Slika 23. - Zapis specijalnog znaka '🙂' preko formata UTF-32.

.... jasno je da se i u ovakvom slučaju (koji je "najmanje dramatičan"), jedan ceo bajt uopšte ne koristi:

UTF-32 02
Slika 24. - U zapisu specijalnog znaka '🙂' preko formata UTF-32, prvi bajt je zauzet, iako se ne koristi .

Po pitanju "rasipanja prostora", stvari su još ozbiljnije kada se zapisuju uobičajeniji UNICODE znakovi ....

UTF-32 03
Slika 25. - Zapis znaka 'Č' preko formata UTF-32.

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

UTF-32 04
Slika 26. - U zapisu znaka 'Č' preko formata UTF-32, dva dodatna bajta su zauzeta, iako se očigledno ne koriste.

Naravno, najviše 'rasipanja' ima u situaciji kada se zapisuju znakovi iz ASCII specifikacije ....

UTF-32 05
Slika 27. - Zapis znaka 'A' preko formata UTF-32.

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

UTF-32 06
Slika 28. - U zapisu znaka 'A' preko formata UTF-32, čak tri dodatna bajta su zauzeta, iako se očigledno ne koriste.

Format UTF-32 (za razliku od formata UTF-16 i UTF-8), nije previše zastupljen u praksi, ali, povremeno se koristi u određenim programima.

Kao što smo već spominjali, za prenos i čuvanje većih količina teksta, najčešće se koristi prilično elegantno rešenje u vidu formata UTF-8 ....

UTF-8

Osnovna ideja koja stoji iza formata UTF-8, podrazumeva kodiranje znakova preko blokova od 8 bita, tako da se znakovi iz ASCII tabele zapisuju preko jednog bajta ("i dalje"), dok se za ostale znakove uvode dodatni bajtovi.

Dakle (da dodatno 'istaknemo poentu'): dodatni blokovi se uvode - samo po potrebi, i stoga nema 'nepotrebnog rasipanja'.

Shodno navedenom, jasno je da format UTF-8 omogućava prostornu uštedu, međutim, zapis viših UNICODE pozicija (slično kao kada se koristi UTF-16), relativno je kompleksan i zahteva nešto više procesorskog vremena pri čitanju i pisanju znakova (u odnosu na prosto čitanje ASCII znakova).

Iako standard UTF-8 nije 'bez nedostataka' (baš kao i ostale pomenute metode kodiranja), upravo se format UTF-8 najčešće koristi za zapis tekstualnih datoteka i kodiranje web dokumenata.

Sve što smo naveli "deluje lepo", ali, glavno pitanje je - kako se ideje sprovode u delo.

Pravila za formiranje kodnih pozicija (sa primerima korišćenja jednog ili dva bajta)

U najpraktičnijem smislu, znakovi iz ASCII specifikacije kodiraju se na isti način kao u samoj ASCII tabeli ....

UTF-8 01
Slika 29. - Zapis znaka 'A' preko formata UTF-8 (praktično: zapis je isti kao u ASCII tabeli) .

.... međutim (kao što smo nagovestili), glavna informacija u smislu enkodiranja ili dekodiranja znaka, sadržana je u prvom bitu:

  • ako je prvi bit 0 - praktično je u pitanju je znak iz ASCII tabele
  • ako je prvi bit 1 - u pitanju je znak sa kodnom pozicijom koja je veća od 127 (i takav znak se kodira uz korišćenje dva ili više bajta)

Na prethodnoj slici, prvi bit nije uključen ....

UTF-8 02
Slika 30. - U zapisu znaka 'A' preko formata UTF-8 (isto važi i za ostale znakove iz osnovne ASCII tabele), jasno je da prvi bit nije uključen. Prvi bit (praktično) sadrži informaciju o tome da li je za zapis znaka dovoljan samo jedan bajt, ili je potrebno uključiti i dodatne bajtove.

.... i upravo je na taj način UTF-8 parseru predata informacija o tome da neće biti potrebno čitati dodatne bajtove (zarad dekodiranja datog znaka), što znači da se znak može pročitati odmah - iz preostalih sedam bitova.

Ranije pomenuta elegancija formata UTF-8, ogleda se u principu koji je prethodno opisan: ASCII je 7-bitni standard, ali (kao što znamo), tipično se prenosi preko osam bita (po znaku), što ostavlja mogućnost da se prvi bit koristi kao prenosilac informacije o tome da li je za dekodiranje određene kodne pozicije dovoljno pročitati jedan bajt (kao u prethodnom slučaju), ili je potrebno čitati i dodatne bajtove.

Ako je (nasuprot prethodnom slučaju), prvi bit uključen, potrebno je očitati bar dva bajta (najbitnije informacije označene su plavom bojom):

UTF-8 03
Slika 31. - Formiranje znaka 'Č' preko formata UTF-8 (u ovom slučaju se koriste dva bajta).

Očitavanje znakova obavlja se prema sledećim opštim pravilima:

  • ukoliko je prvi bit u prvom bajtu 0, kodna pozicija znaka se čita iz prvog bajta (iz preostalih 7 bita)
  • ukoliko je prvi bit u prvom bajtu 1, čitaju se i naredni bitovi, sve dok se ne očita 0
    • broj uzastopnih bitova sa vrednošću 1, na početku prvog bajta, praktično definiše ukupan broj bajtova koji se koriste za kodiranje znaka
    • prva dva bita u preostalim bajtovima, moraju biti redom 1 i 0
    • preko svih preostalih bitova (u svim bajtovima), koji se posmatraju kao jedinstvena niska bitova, * zapisuje se kodna pozicija

* U nastavku ćemo pokazati primer sa slikama (preko koga se lakše može zamisliti raspodela bitova).

Vraćamo se na dekodiranje znaka 'Č' ....

Kada se na prvoj poziciji (u prvom bajtu), pojavi jedinica, potrebno je očitati i drugi bit, i - ako se na drugoj poziciji takođe pojavi jedinica (a na trećoj poziciji nula) ....

UTF-8 04
Slika 32. - Formiranje znaka 'Č' preko formata UTF-8: u prvom bajtu zapisane su dve informacije - broj bajtova koji je potreban za dekodiranje znaka, i deo kodne pozicije.

.... to znači da je za formiranje kodne pozicije potrebno pročitati još jedan bajt (ili, malo drugačije, samo još jedan bajt), odnosno, znači da se dati znak kodira preko ukupno dva bajta.

Drugi bajt mora počinjati kombinacijom bitova 10 ....

UTF-8 05
Slika 33. - Formiranje znaka 'Č' preko formata UTF-8: u drugom bajtu zapisan je - preko poslednjih šest bitova - ostatak vrednosti kodne pozicije (prva dva bita predstavljaju kontrolnu vrednost).

.... a kada se izdvoje preostali bitovi u oba bajta ....

UTF-8 06
Slika 34. - Formiranje znaka 'Č' preko formata UTF-8: preko 11 bitova koji su označeni na slici, zapisuje se vrednost kodne pozicije.

.... dobija se 11 bitova preko kojih je moguće zapisivati znakove sa kodnim pozicijama u rasponu od 128 do 2047 (211 - 1).

Konkretna kombinacija bitova, 100001100, definiše vrednost 268 (256 + 8 + 4), što predstavlja kodnu poziciju znaka 'Č' (sa kojom smo se već susretali u članku).

Svrha kontrolnih bitova (algoritam za proveru)

Kodiranje drugog bajta (odnosno, ostalih bajtova), kombinacijom bitova 10 na samom početku, može delovati pomalo "nepotrebno", ali, u pitanju je kontrolni mehanizam, koji je uveden pre svega zarad situacija u kojima se tekst ne prenosi u obliku datoteka, već, znak-po-znak (streaming), i takav kontrolni mehanizam pruža informaciju o potencijalnim greškama koje mogu nastati u prenosu.

Za početak, uzmimo kao primer situaciju u kojoj se očitava znak koji je kodiran preko dva bajta (pri čemu se na prvoj poziciji uredno pojavio bajt koji počinje sa 110):

  • ako drugi bajt počinje nulom, to je signal da znak nije pravilno enkodiran, što znači da prethodni bajt treba odbaciti (tj. treba formirati kodnu vrednost korišćenjem samo drugog bajta - koji se u navedenim okolnostima prepoznaje kao samostalni "ASCII znak")
  • ako drugi bajt počinje sa 11, to je takođe signal da prethodni bajt treba odbaciti, ali - u ovom slučaju - drugi bajt (koji počinje sa 11), tretira se kao prvi bajt u višebajtnom kodiranju UNICODE znaka *

Prethodno navedenim pravilima - koja važe i u situacijama kada se određeni znak kodira preko tri ili više bajta - dodaćemo još i sledeća pravila:

  • ukoliko se, pri čitanju znaka, bajt koji počinje sa 10 pojavi pre bajta koji počinje sa 110 (ili 1110 i sl) - u pitanju je greška.
  • ukoliko je znak kodiran preko više od dva bajta (tri, četiri i sl), i pri tom bilo koji od bajtova posle prvog ne počinje sa 10 - takođe je u pitanju greška **

* Praktično, u pitanju je "početak novog znaka", i stoga - zarad formiranja vrednosti kodne pozicije - treba prebrojati i ostale jedinice na početku ("novog") prvog bajta, da bi se ustanovilo koliko je dodatnih bajtova potrebno čitati.

Kada se ustanovi koliko (ukupno) bajtova je potrebno pročitati, čita se i sledeći bajt (ili bajtovi), koji mora(ju) počinjati kombinacijom bitova 10.

** U pitanju je greška - bez obzira na to da li je format prethodnih bajtova bio uredan.

Primeri formiranja kodnih pozicija uz korišćenje tri ili više bajtova

Za formiranje kodnih pozicija koje prevazilaze vrednost 2047, koristi se tri ili četiri bajta, * po prethodno opisanom principu: u prvom bajtu je zapisano koliko (ukupno) bajtova se koristi za enkodiranje (tj. dekodiranje) znaka, a ostali počinju sa 10.

UTF-8 07
Slika 35. - Zapis specijalnog znaka preko formata UTF-8, uz korišćenje 3 bajta.

Za enkodiranje znaka uz korišćenje 3 bajta, raspoloživo je 16 bitova, i stoga je maksimalna kodna pozicija koja se može zapisati uz korišćenje 3 bajta: 65535.

Za formiranje kodnih pozicija koje prevazilaze 65535, potrebno je koristiti četiri bajta. *

UTF-8 08
Slika 36. - Zapis specijalnog znaka preko formata UTF-8, uz korišćenje 4 bajta.

U situaciji kada se koristi 4 bajta za enkodiranje znaka, na raspolaganju je 21 bit, i stoga je maksimalna kodna pozicija koja se može zapisati preko četiri bajta: 2097151.

* Teoretski, moguće je koristiti i pet, pa čak i šest bajtova (što možete isprobati u mini-aplikaciji na kraju ovog članka), ali, budući da se preko četiri bajta može zapisati bilo koji znak čija je kodna pozicija između 65536 i 2097151, pri čemu navedena gornja granica osetno premašuje broj znakova koji su trenutno prisutni u UNICODE specifikaciji, formatima koji koriste više od četiri bajta - ne moramo pridavati preveliki praktičan značaj (bar za sada 🙂).

Primer čitanja poruke koja je enkodirana po formatu UTF-8

Da bismo još bolje utvrdili princip kodiranja znakova preko formata UTF-8, razmotrićemo dodatni primer.

Tekstualna datoteka sastoji se iz sledećih bajtova: 196 140 97 197 161 97 ....

UTF-8 09
Slika 37. - Poruka koju treba dekodirati (zapisana preko formata UTF-8).

.... i potrebno je pročitati sadržaj datoteke.

Početak prvog bajta ....

UTF-8 10
Slika 38. - Dekodiranje UTF-8 poruke - korak 1.

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

UTF-8 11
Slika 39. - Dekodiranje UTF-8 poruke - korak 2.

Preko 11 bitova (u prva dva bajta), definisana je vrednost 268 - što predstavlja znak 'Č':

UTF-8 12
Slika 40. - Dekodiranje UTF-8 poruke - korak 3.

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

UTF-8 13
Slika 41. - Dekodiranje UTF-8 poruke - korak 4.

.... što znači da se odmah može pročitati preostalih 7 bitova, u kojima je zapisana vrednost 97, što predstavlja znak 'a':

UTF-8 14
Slika 42. - Dekodiranje UTF-8 poruke - korak 5.

Početak četvrtog bajta (slično kao i početak prvog bajta) ....

UTF-8 15
Slika 43. - Dekodiranje UTF-8 poruke - korak 6.

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

UTF-8 16
Slika 44. - Dekodiranje UTF-8 poruke - korak 7.

.... a preko 'osenčenih' 11 bitova ....

UTF-8 17
Slika 45. - Dekodiranje UTF-8 poruke - korak 8.

.... definisana je vrednost 353, odnosno znak 'š'.

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

UTF-8 18
Slika 46. - Dekodiranje UTF-8 poruke - korak 9.

.... što znači da se znak odmah može dekodirati preko preostalih 7 bitova (ponovo je u pitanju vrednost 97, to jest, znak 'a'):

UTF-8 19
Slika 47. - Dekodiranje UTF-8 poruke - korak 10.

Sadržaj datoteke je (reč): "Čaša".

UTF-8 20
Slika 48. - Dekodiranje UTF-8 poruke - poruka je dekodirana.

Formulari: UTF-8 enkoder / dekoder

Kao što smo ranije nagovestili, formulari u narednim odeljcima mogu poslužiti za isprobavanje 'teorije' sa kojom smo se upoznali kroz članak.

Enkodiranje

Enkoder uzima vrednost iz numeričkog ulaznog polja, vraća detaljan prikaz strukture bitova enkodiranog znaka (strukturu bajtova i dekadne ekvivalente), i ispisuje znak.

Dekodiranje

Dekoder uzima (iz ulaznog polja), niz dekadnih brojeva u rasponu od 0 do 255 (brojevi su razdvojeni razmacima i praktično predstavljaju "bajtove"), a ukoliko niz "bajtova" predstavlja poruku koja je pravilno kodirana po standardu UTF-8, dekodirana poruka će biti ispisana ispod ulaznog polja.

Zaključak / kratka analiza

Iako smo se u članku "podosta napričali" o metodama za enkodiranje i dekodiranje znakova, tema za razgovor (zapravo) ima još ....

Najviše prostora posvetili smo standardu UTF-8 i implicirali smo da navedeni standard (uglavnom) predstavlja optimalno rešenje, međutim, osvrnućemo se i na prilično očigledne nedostatke UTF-8 zapisa:

  • u pojedinim slučajevima, format UTF-8 je manje ekonomičan od formata UTF-16 (primer: ako se koristi format UTF-16, znakovi kineskog pisma mogu se zapisati preko jednog bloka od 2 bajta, a ako se koristi format UTF-8, potrebno je izdvojiti 3 bajta za svaki znak)
  • procedure za enkodiranje i dekodiranja UTF-8 znakova, relativno su komplikovane za implementaciju, i stoga je i enkodiranje (tj. dekodiranje) UTF-8 znakova, nešto sporije

Ako se izraz "win-win" (iz engleskog jezika), odnosi na pogodbe u kojima svaka strana dobija (ili na situacije u kojima sve izlazi na dobro), onda se celokupna situacija sa metodama UTF enkodiranja može shvatiti (pomalo slikovito), kao svojevrsna "lose-lose" situacija (jer nijedna od opcija nije optimalna sama po sebi).

Sa druge strane, nedostaci ni izdaleka nisu "zabrinjavajući", i stoga je najbolje biti praktičan:

  • tamo gde je optimalno koristiti UTF-16, koristi(će) se UTF-16 (isto važi i za format UTF-32, koji, kao što smo već naveli, ipak nije toliko često u upotrebi)
  • programski jezici godinama unazad sadrže funkcije za enkodiranje i dekodiranje po standardima UTF-8, UTF-16 i UTF-32, što znači 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 čitanja ASCII datoteka (sa jedne strane), i UTF-8 datoteka (sa druge strane) - bude praktično 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 zanima da se dodatno upoznate sa tematikom predstavljanja znakova na računarima - alternativne metode za kodiranje znakova mogu biti dobra ideja za početak daljeg istraživanja ....

Autor članka Nikola Vukićević Za web portal codeblog.rs
Napomena: Tekstovi, slike, web aplikacije i svi ostali sadržaji na sajtu codeblog.rs (osim u slučajevima gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog pismenog odobrenja autora.
© 2020-2025. Sva prava zadržana.
Facebook LinkedIn Twitter Viber WhatsApp E-mail
početna > Članci > ASCII, UNICODE i UTF - Predstavljanje znakova na računarima
codeBlog codeBlog
Sajt posvećen popularizaciji kulture i veštine programiranja.
Napomena: Tekstovi i slike na sajtu codeblog.rs (osim u slučajevima, gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog odobrenja autora.
© 2020-2025. Sva prava zadržana.
Facebook - logo
Instagram - logo
LinkedIn - logo
Twitter - logo
E-mail
Naslovna
   •
Uslovi korišćenja
   •
Obaveštenja
   •
FAQ
   •
Kontakt