Kóðun
Eins og við þekkjum eru gögn af ýmsum toga, allt frá texta upp í mynd og hljóð. Þó að þessi gögn séu gríðarlega ólík í okkar huga eru þau öll geymd á nákvæmlega sama máta þegar kemur að tölvum.
Í grunninn geyma harðir diskar, og aðrar gagnageymslur, gögn á sama máta. Við getum ímyndað okkur þessar gagnageymslur sem röð milljarða rofa. Rofana er hægt að setja í tvær stöður, ýmist kveikt eða slökkt. Gögn eru svo geymd í þessum gagnageymslum sem runa af slökkt og kveikt, sem við táknum sem 0 og 1 og köllum bita (bits). Þegar öllu er á botninn hvolft eru því öll tölvutæk gögn geymd sem ein tvíundatala!
Kóðun (e. encoding) er sú aðferð sem beitt er til að framsetningar gagna.
Oftast skiptum við gögnum í tvo flokka, annars vegar textagögn (text data) og hins vegar tvíundagögn (binary data). Í þessum kafla ætlum við að einbeita okkur að kóðun rittákna (e. character encoding).
Textagögn
Textagögn eru þau gögn sem innihalda einfaldan texta, eins og þann sem þú ert að lesa núna. Í þessu kennsluefni táknum við textagögn með þessu útliti og köllum það streng (string).
ASCII
Þar sem tölvur geyma gögn bara sem tölur þá er mikilvægt að allir sammælist um hvaða merkingu tölurnar hafa. Þetta er sérstaklega mikilvægt þegar kemur að textagögnum og reyndi mikið á þetta í árdaga tölvunnar.
Upp úr 1960 var gefinn út svokallaður ASCII (American Standard Code for Information Interchange) staðall sem úthlutaði „öllum“ táknum og bókstöfum sinn tölustaf sem passaði inn í 7 bita tvíundatölu.
| Tugak. | Tvíundak. | Tákn | Tugak. | Tvíundak. | Tákn |
|---|---|---|---|---|---|
| 32 | 0100000 | bil | 80 | 1010000 | P |
| 33 | 0100001 | ! |
81 | 1010001 | Q |
| 34 | 0100010 | " |
82 | 1010010 | R |
| 35 | 0100011 | # |
83 | 1010011 | S |
| 36 | 0100100 | $ |
84 | 1010100 | T |
| 37 | 0100101 | % |
85 | 1010101 | U |
| 38 | 0100110 | & |
86 | 1010110 | V |
| 39 | 0100111 | ' |
87 | 1010111 | W |
| 40 | 0101000 | ( |
88 | 1011000 | X |
| 41 | 0101001 | ) |
89 | 1011001 | Y |
| 42 | 0101010 | * |
90 | 1011010 | Z |
| 43 | 0101011 | + |
91 | 1011011 | [ |
| 44 | 0101100 | , |
92 | 1011100 | \ |
| 45 | 0101101 | - |
93 | 1011101 | ] |
| 46 | 0101110 | . |
94 | 1011110 | ^ |
| 47 | 0101111 | / |
95 | 1011111 | _ |
| 48 | 0110000 | 0 |
96 | 1100000 | ` |
| 49 | 0110001 | 1 |
97 | 1100001 | a |
| 50 | 0110010 | 2 |
98 | 1100010 | b |
| 51 | 0110011 | 3 |
99 | 1100011 | c |
| 52 | 0110100 | 4 |
100 | 1100100 | d |
| 53 | 0110101 | 5 |
101 | 1100101 | e |
| 54 | 0110110 | 6 |
102 | 1100110 | f |
| 55 | 0110111 | 7 |
103 | 1100111 | g |
| 56 | 0111000 | 8 |
104 | 1101000 | h |
| 57 | 0111001 | 9 |
105 | 1101001 | i |
| 58 | 0111010 | : |
106 | 1101010 | j |
| 59 | 0111011 | ; |
107 | 1101011 | k |
| 60 | 0111100 | < |
108 | 1101100 | l |
| 61 | 0111101 | = |
109 | 1101101 | m |
| 62 | 0111110 | > |
110 | 1101110 | n |
| 63 | 0111111 | ? |
111 | 1101111 | o |
| 64 | 1000000 | @ |
112 | 1110000 | p |
| 65 | 1000001 | A |
113 | 1110001 | q |
| 66 | 1000010 | B |
114 | 1110010 | r |
| 67 | 1000011 | C |
115 | 1110011 | s |
| 68 | 1000100 | D |
116 | 1110100 | t |
| 69 | 1000101 | E |
117 | 1110101 | u |
| 70 | 1000110 | F |
118 | 1110110 | v |
| 71 | 1000111 | G |
119 | 1110111 | w |
| 72 | 1001000 | H |
120 | 1111000 | x |
| 73 | 1001001 | I |
121 | 1111001 | y |
| 74 | 1001010 | J |
122 | 1111010 | z |
| 75 | 1001011 | K |
123 | 1111011 | { |
| 76 | 1001100 | L |
124 | 1111100 | \| |
| 77 | 1001101 | M |
125 | 1111101 | } |
| 78 | 1001110 | N |
126 | 1111110 | ~ |
| 79 | 1001111 | O |
127 | 1111111 | DEL |
Dæmi
Breyttu tvíundartölunni
10010001100001110110011011001101111010110001000001101000110010111010011101101111010111100100100001
í ASCII streng.
Lausn
Við getum notað From Binary aðgerðina í CyberChef til að breyta tvíundatölu yfir í streng. Í okkar tilfelli er notast við 7 bita til að tákna hvern staf, en sjálfgefin stilling í CyberChef er 8. Fyrst munum við því fá skrýtna niðurstöðu. Aftur á móti þegar við breytum Byte Length í 7, þá fáum við rétt svar.
Athugið líka að sjálfgefin stilling á Delimiter, þ.e. afmörkunarmerki, er Space eða bil. Það kemur ekki að sök í þessu tilfelli þó að afmörkunarmerkið sé stillt á bil. Oft eru tvíundartölur sem tákna strengi settar fram þannig að bitarnir séu afmarkaðir, t.d. með bili eða hver í sinni línu. Ástæða þess er að stundum eru fleiri (oft átta) bitar notaðir til að tákna hvern staf. Með afmörkunarmerkjum leikur þannig enginn vafi á þeim fjölda bita sem notaður er fyrir hvert tákn.
Bæti
Snemma varð 8 bita tölvukerfið að staðli. Sú hefð lifir enn í dag og er gögnum oftar en ekki skipt niður í 8 bita hópa sem kallast bæti (e. byte). Bæti eru oft táknuð með rithætti sextándakerfisins, en þá er hvert bæti einmitt tveggja stafa tala.
Þessi hefð á ekki síst við þegar talað er um ASCII staðalinn, þannig oft má sjá að í stað þess að tákna ASCII táknið A sem tugakerfistöluna 65 eða tvíundatöluna 1000001, þá er hún táknuð sem 0x41 (eða einfaldlega 41).
Restin af heiminum
Sem Íslendingar sjáum við strax ákveðinn galla á ASCII staðlinum. Það er engin leið til að tákna séríslenska stafi eins og á, ð og þ. Við erum auðvitað ekki eina þjóðin sem notar sérstaka stafi. Aðrar evrópuþjóðir nota sömuleiðis sértákn, svo ekki sé minnst á asísk mál eins og Kínversku og Japönsku sem nota þúsundir sérstakra tákna sem eiga lítið skylt við latneska stafrófið. En í ASCII staðlinum er bara pláss fyrir 128 tákn.
Breytingin yfir í 8 bita tölvukerfi skapaði svigrúm til að tvöfalda fjölda tákna í ASCII-staðlinum með því að bæta við 128 nýjum stöfum í lausu sætin sem mynduðust.
Þetta var nóg fyrir ákveðin málsvæði, en ekki nóg til að tákna alla stafi allra tungumála heimsins. Niðurstaðan var þá að hvert og eitt málsvæði tók upp sinn eigin staðal þar sem 128 nýjum táknum var bætt við ASCII staðalinn.
Ísland notaðist, til dæmis, við staðalinn ISO-8859-1, sem stundum er kallaður Latin 1, sem bætti við táknum sem hentuðu mörgum Vestur-Evrópskum málum. Mið-Evrópsk lönd notuðust við ISO-8859-2, svo dæmi séu tekin. Þessi lausn virkaði ágætlega til að eiga samskipti innan málsvæða, en um leið og samskipti fóru á milli landssvæða flæktist málið.
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
a |
b |
c |
d |
e |
f |
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
a_ |
NBSP | ¡ | ¢ | £ | ¤ | ¥ | ¦ | § | ¨ | © | ª | « | ¬ | SHY | ® | ¯ |
b_ |
° | ± | ² | ³ | ´ | µ | ¶ | · | ¸ | ¹ | º | » | ¼ | ½ | ¾ | ¿ |
c_ |
À | Á | Â | Ã | Ä | Å | Æ | Ç | È | É | Ê | Ë | Ì | Í | Î | Ï |
d_ |
Ð | Ñ | Ò | Ó | Ô | Õ | Ö | × | Ø | Ù | Ú | Û | Ü | Ý | Þ | ß |
e_ |
à | á | â | ã | ä | å | æ | ç | è | é | ê | ë | ì | í | î | ï |
f_ |
ð | ñ | ò | ó | ô | õ | ö | ÷ | ø | ù | ú | û | ü | ý | þ | ÿ |
Gildi sem ISO-8859-1 bætti við ASCII staðalinn, sett fram sem sextándakerfistölur
Segjum sem svo að við viljum senda strenginn Óþýð til Grikklands. Með ISO-8859-1 kóðast tákn (bæti) strengsins sem d3 (211), fe (254), fd (253) og f0 (240), eða
d3 fe fd f0
Í Grikklandi var, aftur á móti, notast við ISO-8859-7. Í þeim staðli samsvara þessi gildi allt öðrum táknum, þ.e. Σ, ώ, ύ, og π, og myndi því strengurinn skila sér til Grikklands sem Σώύπ.
Önnur kerfi
Margir staðlar spruttu upp sem reyndu að fullnýta 256 „plássin“ sem bætið hafði upp á að bjóða. Í einhverjum tilfellum var það þó ekki nóg, og var þá gripið til þess að notast við fleiri bæti.
Sumar kóðanir notuðust ávallt við sama fjölda bæta fyrir hvert tákn, eins og UCS-2 sem notar 2 bæti (65,536 möguleg tákn) fyrir hvert tákn og UTF-32 sem notar 4 bæti (4.294.967.296 möguleg tákn). Aðrar kóðanir notuðust við breytilegan fjölda bæta fyrir hvert tákn.
Unicode
Unicode samtökin voru seinna stofnuð til að komast að samkomulagi um eitt kerfi sem hægt væri að nota til að kóða texta allra tungumála heims. Unicode staðallinn úthlutar öllum táknum kóðgildi (code point) sem er einfaldlega tala sem auðkennir það tákn.
Kóðagildi tákna í Unicode eru táknuð sem U+HHHH þar sem HHHH er auðkennisnúmer táknsins sem sextándakerfistala. Fyrir táknin sem eru í ASCII staðlinum heimfærast gildin nákvæmlega yfir. Þannig er kóðagildið fyrir bókstafinn A U+0041 og upphrópunarmerki U+0021, svo dæmi séu tekin.
Unicode staðallinn er gríðarlega umfangsmikill og fangar miklu meira en bara bókstafi, en í honum má finna tákn úr dauðum málum og híróglífur, rúnir, broskalla, fána, skáktákn og margt margt fleira.
UTF-8
Sú kóðun sem náð hefur mestri útbreiðslu í dag er UTF-8 (Unicode Transformation Format), sem er útfærsla á Unicode staðlinum og yfir 99% vefsíða heimsins nota. UTF-8 er í rauninni útvíkkun á ASCII sem notast við breytilegan fjölda bæta fyrir hvert tákn. Gildin 0 upp í 127 samsvara þannig ASCII gildunum og því er hægt að lesa ASCII kóðaðan streng rétt sem UTF-8. Önnur tákn eru svo framsett með einu til fjórum bætum. Íslenski stafurinn þ er til dæmis kóðaður sem fe (U+00FE), gríski stafurinn Ω (Omega) er kóðaður sem ce a9 (U+03A9) og broskallinn 🙂 sem f0 9f 99 82 (U+1F642).
ATH
Við sjáum að stundum er samræmi milli kóðagildis og kóðunarinnar, eins og með þ sem er kóðað sem fe og hefur kóðagildið U+00FE, en stundum er ekki samræmi eins og með kóðun Ω, ce a9, sem hefur kóðagildið U+03A9. Ástæðan fyrir því er að það er ekki bein samsvörun milli kóðagildisins, sem getur verið allt að fjögur bæti, og kóðunarinnar. Ef það ætti að vera bein samsvörun á milli þeirra, yrðu öll tákn að hafa fjögurra bæta kóðun. En þar sem UTF-8 framkallar mislangar kóðanir, þá eru ákveðnir bitar í kóðuninni notaðir til að geyma aukaupplýsingar, eins og hversu löng kóðunin er.
Ef við skoðum kóðunina á Ω í tvíundaformi, þá er hún
11001110 10101001
UTF-8 staðallinn segir að ef bæti byrjar á 110, þá sé það fyrri hluti af tveggja bæta kóðun. Seinna bætið byrjar á 10, sem UTF-8 staðallinn kallar framhaldsbæti (e. continuation byte). Ef við fjarlægjum þessa hluta bætanna og skeytum saman, þá fáum við kóðagildið sem um ræðir:
Dæmi: UTF-8
Hvað hefur eftirfarandi UTF-8 kóðun að geyma?
01001000 01100001 01101100 01101100 11000011 10110011 00100000 11110000 10011111 10011000 10001010
Lausn
Við getum notað From Binary aðgerðina í CyberChef til að breyta tvíundatölu yfir í streng. Sjálfgefin stilling á þeirri aðgerð er að nota 8 bita per bæti og bil til að afmarka þau. Strengurinn okkar er einmitt þannig og þurfum við því ekki að breyta þeim stillingum.
CyberChef er frekar klár og þegar við höfum lesið tvíundatöluna og breytt henni í streng, þá áttar hann sig á því að þetta sé UTF-8 strengur og gefur okkur rétt gildi. Fyrsta skrefið er því nóg í þessu tilfelli. Aftur á móti er það ekki alltaf víst að þessi ágiskun hjá CyberChef virki.
Til að ganga úr skugga um að CyberChef velji rétta kóðun, getum við nota Encode text aðgerðina og valið UTF-8.
UTF-16
Önnur algeng útfærsla á Unicode staðlinum er UTF-16. Á meðan UTF-8 notar lágmark eitt bæti (8 bita) til að tákna staf, þá notar UTF-16 lágmark tvö bæti (16 bita).
Þetta hefur mjög mikilvægar afleiðingar. Vegna þess að UTF-16 notar alltaf að lágmarki tvö bæti fyrir hvern staf, þá er ekki hægt að lesa ASCII kóðaðan texta sem UTF-16, á sama hátt og hægt er með UTF-8.
Ef við skoðum ASCII táknið A (sem er 65 eða 0x41 í sextándakerfinu), þá er það einfaldlega táknað sem eitt bæti, 41, bæði í ASCII og UTF-8. Í UTF-16 væri það hins vegar oftast táknað með tveimur bætum, t.d. sem 41 00. Þetta þýðir að ef gamalt forrit reynir að lesa UTF-16 skjal sem inniheldur stafinn A, þá gæti það misskilið auka 00 bætið sem sérstakt núll-tákn (e. null byte), sem veldur því að lesturinn á textanum stöðvast eða brotnar.
Bætaröð (Endianness)
Þegar tölvur vinna með gögn sem taka meira en eitt bæti, eins og tveggja bæta stafina í UTF-16, þurfa þær að ákveða í hvaða röð bætin eiga að vistast. Þetta er kallað bætaröð (e. endianness eða byte order).
Við getum vistað bætin á tvo vegu:
- Háendaframsetning (e. Big Endian eða BE): Hér er stærri hlutinn ritaður fyrst, alveg eins og í hefðbundnu talnakerfi (t.d. í tölunni 15, skrifum við tuginn 1 á undan einingunni 5). Kóðunin fyrir
Aer þá00 41. Þetta er oft kallað UTF-16BE. - Lágendaframsetning (e. Little Endian eða LE): Hér er minni hlutinn ritaður fyrst. Kóðunin fyrir
Aer þá41 00. Þetta er oft kallað UTF-16LE.
Þó að þetta kunni að hljóma einkennilega er mjög mikilvægt að hafa hugfast að þessar tvær framsetningarleiðir bæta eru í boði og báðar eru notaðar. Bætaröð skiptir ekki bara máli þegar kemur að kóðun rittákna, heldur hefur hún gríðarlega þýðingu í allri tölvunarfræði. Sem dæmi má nefna að netsamskipti eru yfirleitt með hánedaframsetningu en örgjörvar notast yfirleitt við lágendaframsetningu.
Vissir þú?
Stýrikerfið Windows notar UTF-16LE á bak við tjöldin sem sinn staðal fyrir texta. Þetta var ákveðið snemma á tíunda áratugnum, mörgum árum áður en UTF-8 sló í gegn og varð ríkjandi staðallinn á vefnum. Oft þarf því hugbúnaður sem keyrir á Windows stöðugt að breyta texta fram og til baka á milli UTF-16LE og UTF-8.
Fróðleikur: Ekki bara tvö bæti!
Athugið að bætaröð á ekki bara við þegar við tölum um tveggja bæta gildi eins og í UTF-16. Hugtakið gildir jafnvel jafnramt um stærri tölur eins og fjögurra eða átta bæta gildi, eins og þegar tölvur eru að eiga samskipti yfir net (IP-tölur eru fjögur bæti) eða þegar örgjörvar framkvæma 64-bita útreikninga. Ef við höfum fjögurra bæta háendatöluna 11 22 33 44, þá vistast hún algjörlega aftur á bak í minni sem lágendatalan 44 33 22 11.
Dæmi: UTF-16
Hvaða strengur hefur verið kóðaður hérna með UTF-16 (Big Endian)?
00 4e 00 65 00 74 00 f6 00 72 00 79 00 67 00 67 00 69
Lausn
Til að breyta sextándakerfistölu í streng notum við fyrst From Hex. Eftir að við beytum þeirri aðgerð á textann, þá sjáum við að við endum með einkennilega niðurstöðu á borð við
␀N␀e␀t␀ö␀r␀y␀g␀g␀i
sem inniheldur skrýtið tákn á milli allra stafanna. Ástæða þess er að CyberChef reynir að lesa niðurstöðuna sem UTF-8 og túlkar þannig auka 00 bætin sem svokallað núll tákn (e. null).
Við notum því næst aðgerðina Decode text og veljum UTF-16BE og fáum þá rétta niðurstöðu.
Dæmi: UTF-16
Hvaða strengur hefur verið kóðaður hérna með UTF-16 (Big Endian)?
28 00 6f 25 b0 00 a1 25 b0 00 29 00 6f 25 35 fe 20 00 3b 25 01 25 3b 25
Lausn
Eins og í fyrra dæminu notumst við við From Hex aðgerðina og Decode text með UTF-16LE og endum þá með strenginn.
EBCDIC
Þó að ASCII, ISO-8859 og að lokum Unicode (UTF-8 og UTF-16) hafi orðið algjörlega ráðandi í heiminum, þá er vert að minnast á eitt annað sögulegt kerfi, EBCDIC (Extended Binary Coded Decimal Interchange Code).
EBCDIC var hannað af IBM á sama tíma og ASCII kom fram og var aðallega notað á stórtölvum þeirra (e. mainframes). Það sem gerir EBCDIC mjög áhugavert er hversu gjörólíkt það er ASCII. Í ASCII er t.d. stafirnir A til Z í röð (65 er A, 66 er B, o.s.frv.), en í EBCDIC eru „göt“ í miðju stafrófinu! Auk þess eru tölustafirnir 0 til 9 kóðaðir ofar en bókstafirnir í stað þess að vera neðar eins og í ASCII.
Þótt mjög fáir noti EBCDIC í dag utan IBM-stórtölvukerfa (sem mörg stór fjármálafyrirtæki nota raunar ennþá), minnir það okkur á mikilvægi þess að vita hvaða staðal verið er að nota. Ef við túlkum EBCDIC gögn sem ASCII endum við með einhverja vitleysu. Þar að auki minnir þetta okkur á að allir staðlar snúast einfaldlega um val. Það er ekki heilagur sannleikur að 65 þurfi að tákna A. Það var einfaldlega val á sínum tíma og hefðin hefur haldið því vali gangandi, meðal annars til að halda samræmi við eldri texta.
Grein í Tölvumálum frá 1991
Jóhann Gunnarsson skrifaði skemmtilega grein um kóðun rittákna í Tölvumálum og þá ringulreið sem ríkti á þeim tíma þegar kom að framsetningu ólíkra tungumála á tölvutæku formi. Greinin er einmitt skrifuð á sama tíma og verið var að vinna að Unicode staðlinum.