Karakterek kódolása

A Programozás Wiki wikiből

A karakterkódolás egy eljárás arra, hogy egy karakterkészlet egy-egy karakterét előre meghatározott jelek csoportjává alakítsuk, azok tárolása vagy továbbítása céljából. A képzett jel lehet akár bitcsoport, akár szám, vagy impulzussorozat, vagy bármi más ami illeszkedik a tároláshoz, ill. a továbbításhoz. Az informatikában legtöbbször a kódolás bájtokká, vagy azok sorozatává történik.

Már az elején le kell szögezni, hogy ez alatt a fogalom alatt többféle dolgot értünk:

  • Milyen kódlapot, vagy kódlapokat használunk a kódolási eljárásban
  • A kódlap(-ok) alapján előállt bináris értékek milyen eljárással kerülnek tárolásra, továbbításra az adathordozó tulajdonságait figyelembe véve
  • Egy szövegen belül milyen eljárást, jelölési módot alkalmazunk a szöveg kódlapjához nem tartozó, vagy meg nem jeleníthető karakterek megadására

Kódlapok[szerkesztés]

A kódlapok valójában táblázatok, amikből kiolvashatók, hogy egy adott bináris érték (bitkombináció) melyik karaktert kódolja. Ugyanez visszafelé is működik: a karakter ismeretében a táblázatból kikereshetjük a bitkombinációt. Kis -pl. 8 bites - kódlap esetén ez utóbbi nem mindig végezhető el, mert lehet, hogy az adott karaktert nem tartalmazza a kódlap. Ez utóbbi esetben lehet, hogy másik kódlapot kell választanunk a szöveg kódolásához. Az is előfordulhat, hogy egy kódlap olyan bitkombinációkat tartalmaz, amelyekhez nem tartozik karakterkép (vagy vezérlőkarakter). Ekkor kérdéses, hogy mi történjen a szöveg láthatóvá tételekor. Ezt általában - önkényesen - maga a megjelenítő program dönti el. Vagy egyáltalán nem veszi figyelembe ezt a kódot, vagy pedig valamilyen helyettesítő karaktert, vagy karaktersorozatot használ ezekre az esetekre.

Egyes - régebbi - kódrendszerek több kódlapot alkalmaztak. Ez volt pl. a telexnél használt 5 bites Baudot kódolás, ahol volt "betűváltó" utáni kódlap, és volt "számváltó" utáni kódlap. A kétféle váltó valójában egy-egy vezérlő karakter volt (dec 31 és 27 kódok), ami megadta, hogy a megjelenésüket követően betűként vagy számként, ill. írásjelként kellett értelmezni ugyanazt az 5 bites kódot. Hasonló volt egy ősi - egyetemi számítóközpontokban használt - Optima szalaglyukasztó írógép kód, ami shifteletlen (kisbetűs) esetben más karaktert jelentett, mint shiftelten (nagybetűs). Itt is voltak váltó karakterek.

A különböző kódlapok kialakulásának több oka is van:

  • Egy adott cég egy eszközhöz önkényesen - esetleg más forrásokból merítve - kitalált egy kódlapot. Talán éppen ez a magyarázata a sok egymáshoz nagyon hasonló kódlapnak, ahol is jóhiszeműen egy létező kódlapot módosítottak: vagy kiegészítve a nem definiált értékeknél további karakterekkel (pl. CP437 a DOS-ban), vagy egyes ritkán használtnak vélt karaktereket helyettesítették az adott feladathoz feltétlenül szükséges jelekkel (pl. egy ősi, magyar ékezetes kód a 7 bites ASCII átfaragásával egyes magyarított nyomtatóknál).
  • A nemzeti karakterek szükségességének egyre égetőbbé válásával egy cég vagy egy közösség kialakít egy vagy több kódlapot, ill. kódlapcsaládot. Az eljárás az előbbi két módszert követi, de gyakran figyelmen kívül hagyja a megcélzott csoport egyik vagy másik érdekét. Ez történt Magyarországon a privát ötletű CWI kódlappal (CP437-ból), vagy az SZKI-hoz köthető kiadványszerkesztő kódlapjával. Ugyanez lejátszódott a MS történetében, kezdve a CP850-852 családdal, majd folytatva a Latin1, latin2, stb. becenevű, később ISO-8859-ként szabványosult kódlapcsaláddal. Egy harmadik módszert kellett azonban alkalmazniuk a keleti népeknek a nemzeti karaktereikhez. Itt a terjedelmes mennyiségű jel miatt a karakterek nagy részét értékpárok kódolták. Úgy is fel lehetett fogni, hogy egy karakterkészletet nagyon sok kódlap kódolt, és egyes bitkombinációk kódlapot váltottak az azt követő kódértékre vonatkozólag.

A várva várt egységes megoldást az Unicode szabvány hozta, amely egyik oldalról (majdnem) megoldotta az összes nemzet karaktereinek problémáját úgy, hogy szakított a 8 bites kódlapokkal. Ám ez utóbbi - azaz a 16 bites kódolás - újabb problémákat szül.

Belső kódolás[szerkesztés]

A mikroprocesszorok és a bájt-fogalom (8 bit) széleskörű elterjedésével a 8 bites kódlapok karaktereinek kódolása és továbbítása (az átvitelben is a 8 bit terjedt el leginkább) problémamentessé vált. A korai (szekrény méretű) nagygépek gépi szavaiba zsúfolt karakterek sorrendjének, belső kódjainak problémái a PC-kben és egyéb mikroszámítógépekben megszűntek. Pár évtized alatt ez annyira megszokottá vált, hogy az Unicode megjelenésével új helyzet állt elő. Továbbra is 8 biten szerették volna az alkalmazások a szövegeket kezelni, csupán átvéve egy új kódlapot, ami azonban 16 bites volt. Erre alakították ki az UTF-8 kódolási eljárást, ami azonban változó hosszúságú karakterkódot eredményezett. Míg az ASCII kódok megmaradtak, a további karakterek egy részét 2 bájt, más részét 3 illetve 4 bájt kódolta le (a görög betűk pl. 3 bájtosak). Nem csak ez az átkódolás létezik, van UTF-7 is, és néhány más - ritkán használt - módszer is.

Külön probléma jelentkezett a 16 bites kód esetén a bájtsorrend (endianness) tekintetében. Ugyanis a 16 bites kód akár nyersen is - azaz 2 bájtban - eltárolható, azonban ennek bájtokká tördelése esetén nem mindegy, milyen sorrendben jön a felső és az alsó 8 bit. Ez egy régi probléma abból az időből, amikor a bájtszervezés általánossá válásával 8 bitesnél hosszabb értékeket is el kellet tárolni a memóriában. A Motorola processzoroknál elterjedt big-endian (nagy a végén) módszernél növekvő bájtcímek mellett először a felső, majd az alsó bájt kerül tárolásra. Adatátvitelnél is a felső bájt kerül ki először, utána az alsó. Az interneten is ez terjedt el. Intel processzoroknál ez fordítva van. Először - kisebb memóriabájt címen - jön az alsó 8 bit, aztán a felső következik. Ez a little-endian (kicsi a végén) bájtsorrend. A 16 bites Unicode (UTF-16) kódolású szövegfájlokban szokás az első karakternek a BOM (Byte Order Mark) karaktert megadni, ami alapján megállapítható a bájtsorrend. Ez a karkater a hexa FEFF kódú "Zero Width Non Breaking Space" karakter, amelynek fordítottja - a hexa FFFE érték - definíciószerűen nem Unicode karakter. Ha tehát az első szó ez utóbbit tartalmazza, akkor a bájtsorrendet meg kell fordítani. Ez a kód egyébként jelzi azt is, hogy Unicode szövegfájlról van szó. Ugyanez szokott szerepelni UTF-8 kódolású szövegfájlokban is 3 bájtossá kódolva hexa EF BB BF értékként.

Az UTF-8 kódot kezelő programokban probléma van a karakterek indexelésénél. Ez ugyanúgy jelentkezik, mint a keleti népek kétbájtossá kódolt nemzeti karaktereinél. Amíg eddig egy egyszerű indexeléssel a karakterláncban bármelyik karaktert elérhettünk a sorszáma szerint, itt a változó karakterméret miatt ez nem lehetséges. Csak akkor tudunk ilyet megtenni, ha az UTF-8-at 16 bites karakterekké vagy valamelyik kódlap szűkös karakterkészletévé konvertáljuk.

Egy szintén élő probléma a szövegekben az újsorjel kódolása. Erre is több megoldás terjedt el. A kezdeti DOS, majd az abból kinőtt windowsos rendszerben a CR és LF karakterek (ASCII hexa 0D 0A), egymásutánja jelzi az újsort. UNIX és Linux rendszerekben csupán az LF (ASCII hexa 0A), Macintosh gépeknél pedig a CR (ASCII hexa 0D) karakter. Megjegyezendő, hogy az őskövület telex (Baudot) kódban CR LF CR sorozatot használtak az átvitelkor. De nyomokban létezik olyan módszer is, hogy a fentiektől eltérő, külön vezérlókód (hexa 84) jelzi a sor végét. Igencsak elkeserítő látvány, ha nem ismeri fel a szövegszerkesztő az "újsorjel-nyelvjárást", mivel ilyenkor a sorokra tördelt szöveg helyett gyakran szöveggel teleírt, áttekinthetetlen ablakot kapunk eredményül.


Szöveges kódolások[szerkesztés]

Egy programozó számára nagyon gyakori, hogy egy szövegen belül olyan karaktert kell megadni, ami vagy nem vihető be billentyűzetről, vagy a használt szövegszerkesztő által formátumozásként észlelt karakter. Előbbiek pl. az ASCII vezérlőkarakterek, utóbbiak - az előbbiek közül - a CR, LF és HT (tabulátor) karakterek. Szintén gond lehet a programszöveg szerkesztőbe be nem írható egyes ékezetes, vagy speciális karakterek megadása még akkor is, ha a szerkesztett szöveg kódlapjához tartozik. De végképp problémát okozhat, ha szövegszerkesztő kódlapja eltér attól, amit a program majd használ. Az egyes programnyelvekbe beépített ilyen helyettesítő módszerek manapság nagyon változatos kavalkádot mutatnak, amelyben ember legyen a talpán, az aki ki tud igazodni.

A C nyelv elsők között volt, aki alkalmazta az un. escape szekvenciákat a szövegkonstansokban, azaz amikor ezeket a speciális jeleket fordított törtvonal (\ =backslash) után megadott karakterrel kellet jelölni. Ezek: \n = újsorjel, \t = tabulátor, \b = backstep (visszatörlés), \r = CR (kocsivissza), \f = FF (lapdobás), \\ = backslash (\), \" = " (idézőjel), \' = ' (aposztróf), \nnn = oktálisan megadott karakterkód. Ezt a módszert több helyütt átvették, ill. ki is bővítették más nyelvek.

A Pascal nyelv nem alkalmazta ezt a módszert. Ott karaktert, illetve karakterláncot aposztrófok között lehetett megadni, és csak az aposztróf szövegbe illesztésére volt megoldás: meg kellett kettőzni. Egy egyedülálló aposztróf karakter tehát így nézett ki: ''''. A Borland Turbo Pascalja azonban beépítette a nyelvbe a karakteres konstansok egy másik formáját: a # karakter után megadott egész érték kódolta a karaktert (ez a módszer a C nyelv \nnn megfelelője). Karakterláncot ezek egymás után írásával is kaphattunk, illetve azt közvetlenül aposztrófos szövegkonstanssal folytathattuk, vagy a szövegkonstanst folytathatuk ílymódon megadott karakterekkel. Tehát az előzőek: #13#10 (vagy #$D#$A) = újsorjel, #9 = tabulátor, #8 = backstep, #13 (vagy #$D) = CR, #12 (vagy #$C) = lapdobás (A Turbo Pascalban a $ jel vezeti be a hexa értéket). Ez a megoldás a Delphi Object Pascaljában is megmaradt, és kompatibilitási okokból a Free Pascal is átvette.

Egy ma elterjedt módszer karakterek megadására az SGML karakter entitásnév használata, amelyet a HTML-ben is közismert. Formailag az entitásnevet egy et jellel (& =ampersand) vezetjük be és pontosvesszővel zárjuk (gyakori hiba, hogy a pontosvessző lemarad)! Az entitásnevekben kis és nagybetűk (megkülönböztetetten), számjegyek, illetva a minusz jel (-) és a pont (.) szerepelhetnek, maximum 8 karakter hosszan. Használatukkor a szabványos elnevezéseket kell követni, nem pedig az emberi logikát, ami időnként eltér a szabványtól. Ahol ebben a formában az entitásnevek használhatók (pl. HTML), ott nem használható külön karakterként az et jel, hanem helyette a & entitásnevét kell alkalmazni!

Külön - a programozókat őrületbe kergető - kérdés, hogy egy adott nyelvben a fordító vagy az értelmező mikor helyettesíti az entitásneveket a tényleges karakterré, és mikor adja tovább változatlan formában. Különbség lehet magában a programszövegben, a hozzá tartozó megjegyzésekben és a programszöveg részekén megjelenő szövegkonstansokon belül, különösen akkor ha azok több formában is előfordulhatnak. Ezt a problémát jól ismerik azok, akik HTML oldalt készítenek PHP betétekkel, ahol két (pontosabban 3) féle szövegkonstans megadási mód van. Utóbbiakban MySql esetén SQL parancsokat is megadhatunk, amiken belül szintén lehetnek karakterlánc-konstansok (string a stringben). Ilyenféle esetekben a programozónak alaposan oda kell figyelnie mikor milyen karakterkód megadási formát használhat.

Egy gyakran megengedett lehetőség, hogy a szabványos Unicode értékkel hivatkozunk a karakterre. Ez legtöbbször az SGML entitásnév helyett használható, ahol is az &# jelek és a pontosvessző (;) között megadjuk az értéket vagy decimálisan, vagy x-szel kezdve hexában. Pl. így az ő betű: ő ill.ő. Máshol az Unicode értéknél használni kell az U+xxxx (16 bites kód) illetve az U-xxxxxx (32 bites 0..10FFFF értékek) formát, amit az Unicode szabvány ír elő.

A sokféle, ritkábban használt módszer közül egy gyöngyszem az RFC1345-ben definiált igen tömör forma. Itt legtöbb esetben két, esetleg 3 karakteres mnemonik specifikálja a karaktert (bár vannak elvétve 4-7 karakteres mnemonikok is). Valójában az RFC1345 ezt a formát a kódlapok megadására használja az ASCII kódú szövegfájlban, hogy ne kelljen a teljesen egyértelmű, de terjedelmes Unicode karakter elnevezéseket alkalmazni. Ebben a kódolásban pl. az ő betű az o" karakterpár.


Történelem[szerkesztés]

Még a számítástechnika-mentes időkből ismertek pl. Morse kódok (1840), vagy pl. a Braille írás kódjai (1821). Szintén használatos volt már - szövegek átvitelére az ősi telex gépeken - a Baudot kódolás (1870).

A népszerű ASCII és a hírhedt párja az EBCDIC szinte egy időben (1963) született.

Az ASCII kódokra épült később számos más kódrendszer, amelynek nagy része arra lett volna hivatott, hogy a nemzeti karaktereket (magyarban az ékezeteseket) meg lehessen jeleníteni. A nemzeti kezdeményezések mellet a szoftvergyártó cégek is jeleskedtek, az egyre terebélyesedő kódlapbábel kimunkálásában. Ezeknek az eltérő kódlapoknak a használata még ma is sok hibalehetőség forrása.

Ugyancsak az ASCII-re épül az 1988-ban útjára bocsájtott, és azóta is fejlődő Unicode kódrendszer, mely eredetileg 16 bites kódokkal indult. Hamarosan azonban - főleg a keleti népek temérdek írásjelének nyilvánvalóvá válásával - ez ki lett bővítve 32 bitesre, melyből ma csupán 21 bit (pontosabban a 0..0x10FFFF értékek) ad érvényes kódot.

Magyar ékezetes történelem[szerkesztés]

Már a PC DOS-os korszakában felmerült, hogy helyesírás szerint hibátlan magyar nyelvű szövegeket tároljunk, ahelyett hogy ékezet nélküli vagy valamiféle távirati (pl. csütörtök helyett csuetoertoek) jelölést használnánk. Noha egy rövid időre még magasabb körökben is igyekeztek egyesek az ékezet mentes jelölést elfogadtatni, végül is a "nadrágszár" szavunk őket is meggyőzte arról, hogy ez komoly félreértések forrásává válhat.

Eleve adott volt a PC-n a CP437-es kódlap, melyet kikerülni akkor a kezdetleges CGA és HGC (Hercules) kártyákon csak grafikus módban volt lehetséges. A teljes magyar ékezetes karakterkészlet használatára már akkor is egymás mellett két módszer terjedt el. Az egyik az SZKI által használt Ventura kiadványszerkesztő PC-s változatának megoldása, amely grafikus módban dolgozva felhasználta a CP437-es kódlap ékezetes karaktereit, és a többi - számára érdektelen - kódok helyére további olyan karaktert definiált, amely az európai nyelvekben honosak. Ennek minimális módosításával jött létre az SZKI-nak becézett kódlap. A másik irányzat az igényes informatikusoktól ered, akik igyekeztek magyar ékezetesnek azokat a karaktereket használni, amelyek a legjobban hasonlítottak az eredetihez. Ily módon még karakteres módban is jól olvasható magyar nyelvű szövegek írására volt lehetőség. Az EGA kártyák megjelenésével pedig még karakteres módban is helyes formájú karaktereket lehetett megjeleníteni, mivel a kártya karaktergenerátora (a fontok) átírhatók lettek. Ezt az irányzatot karolta föl az idő tájt a Computerworld-számítástechnika újság és igyekezett elérni, hogy az olvasói vélemények alapján egy egységes kódrendszer álljon elő. Ez majdnem sikerült. Ezt lett a CWI kódlap. Ám fönnmaradt még egy változata ami csak a nagy hosszú i betűben különbözött, és már széleskörűen használatban volt. Eképpen végül is még két kódlapunk született az SZKI mellett: a CWI-1 és a CWI-2.

Mikorra a kedélyek már nagyrészt megnyugodtak - az EGA kártya térhódítása kapcsán - előállt a Microsoft a CP852-vel, arcul csapva a hazai próbálkozásokat. Hamarosan ezt magyar szabványként definiálták azok, akik a számítástechnika akkori irányításában vettek részt, nem törődve a felhasználók véleményével. A helyzetet tovább szépítette, hogy közben a Windows fejlesztése is folyt, és használata egyre népszerűbbé vált. A Microsoft a Windows-ban szakított a CP437-tel és a DOS-hoz használt CP852-vel, és egy új kódlapot hozott létre a Közép-Európa népei számára, ami később az ISO 8859-2 néven vált szabvánnyá. Utóbbinál a hosszú ő betűnél gondok támadtak az angol nyelvű verziókban, ahol a felhasználók - a magyar fontok hiánya miatt - nem tudtak megegyezni, hogy a kalapos vagy a hullámos ő-t használják. Így ebből is rögtön mind a kétféle elterjedt.

Ezen a helyzeten próbált úrrá lenni - az egyébként jól sikerült - MULTIKEY program, ami DOS alatt, rezidensen a memóriában maradva lehetővé tette mind a hat kódlap használatát, könnyedén váltva közöttük. E mellet hallatlan előnye volt az is, hogy az akkor még kiforratlan billentyűzetkiosztást is rugalmasan kezelte, teljesen testreszabhatóvá téve az ékezetes karakterek - és egyéb jelek - helyét, s egy pillanat át lehetett váltani a testreszabott ill. az eredeti kiosztás között. Az 1990-es évek elejét írtuk akkor, a W95-nek még híre-hamva se volt!

A Windows terjeszkedésével a zűrzavar eszkalálódott. Az emberek hol DOS-ban, hol a Win 3.1 alatt dolgoztak, a Windows alá a MULTIKEY-hez hasonlóan sokoldalú eszközt nagyon körülményes lett volna fejleszteni, a Microsoft nem igazán értette a nemzeti karakterek problémáját és nem törődött vele. A Windows NT megjelenésével és az Unicode támogatásával pedig előállt az UTF-8 kódolás, újabb bonyodalmakkal. A webszerkesztés (benne PHP, MySql) mai állapotát figyelve, még csaknem 20 év múltán számos probléma forrása ez a kódlapdzsungel. Emellett az időnként fel-felbukkanó régi DOS állományok megtekintése, átkonvertálása meglehetős izzadságot kíván a felhasználótól. S hiába látszott egy évtizeddel ezelőtt az Unicode kódrendszer mindent megoldó csodaszernek, a bájt alapú UTF-8 használata csak további problémákat szült a karakterlánc kezelés területén.

Csak a teljesen szószervezésű (16 vagy 32 bites) szöveges állományok, és az ilyet kezelni tudó alkalmazások tömegessé válása, továbbá az adatátvitelben a szószervezés térhódítása szüntetné meg a gondokat. Ez ugyan a tárhelyek méretét és a szöveginformációk átvitelének idejét megkétszerezné, vagy megnégyszerezné, ám ha belegondolunk, hogy a világon a multimédiás kép és hang anyagok mennyiségéhez képest a szöveges adatmennyiség csupán apró töredéket jelent, akkor ennek az álomnak lehet realitása.