This is an old revision of the document!
Table of Contents
Karakterkódolás
A számítógép minden adatot bitek formájában tárol. Ez a szövegekre is igaz: a betűket, számjegyeket, írásjeleket és egyéb jeleket tároláskor számsorozattá kell alakítani. A karakterkódolás szabályai határozzák meg, hogyan lesz a karakterekből bájtsorozat, és hogyan állítható vissza abból a szöveg.
Mérnöki munkában karakterkódolással találkozhatunk például mérési eredmények exportálásakor, CSV-fájlok megnyitásakor, műszerek adatainak feldolgozásakor vagy műszaki dokumentumok átvitelekor. Ha az író és az olvasó program eltérő kódolást feltételez, a magyar ékezetek és a műszaki jelek hibásan jelenhetnek meg.
Karakter, kódpont és bájt
A kódolás megértéséhez három fogalmat különböztetünk meg:
| Fogalom | Jelentés | Példa |
|---|---|---|
| Karakter | A szöveg egyik jele. | Az ó betű. |
| Unicode-kódpont | A Unicode rendszerében a karakterhez rendelt számazonosító. | U+00F3 |
| Kódolt bájtsorozat | A karakter tárolási alakja egy adott kódolásban. | UTF-8 esetén C3 B3. |
A táblázatban a kódpont és a bájtok értékei hexadecimális, azaz tizenhatos számrendszerben szerepelnek. Az U+ jelölés Unicode-kódpontra utal; nem része a fájlban tárolt szövegnek.
Egy bájt 8 bitből áll, ezért 256 különböző értéket vehet fel. Egy karakter tárolásához azonban nem feltétlenül elegendő egyetlen bájt.
A karakterek száma és a tároláshoz szükséges bájtok száma nem feltétlenül egyezik meg.
ASCII és a régi kódlapok
ASCII
Az ASCII (American Standard Code for Information Interchange) egy 7 bites karakterkód. A 7 bit összesen 128 különböző kódértéket tesz lehetővé.
Az ASCII tartalmazza:
- az angol ábécé 26 nagybetűjét és 26 kisbetűjét;
- a tíz számjegyet;
- írásjeleket és néhány műveleti jelet;
- a szóközt és a vezérlőkaraktereket.
A vezérlőkarakterek nem megjelenítendő betűket jelölnek. Ilyen például a tabulátor, a soremelés (LF) és a kocsi-vissza (CR). Szövegfájlokban a sor végét egyes rendszerek LF-fel, mások CR és LF egymás utáni használatával jelölik. Ez a különbség nem azonos a karakterkódolások eltérésével.
| Karakter | Decimális ASCII-kód | Hexadecimális ASCII-kód |
|---|---|---|
| Szóköz | 32 | 20 |
| 0 | 48 | 30 |
| A | 65 | 41 |
| a | 97 | 61 |
Az ASCII önmagában nem tartalmazza a magyar ékezetes betűket. Például az ő és az ű nem ábrázolható vele.
Megjegyzés: Bár az ASCII 7 bites kód, a gyakorlatban rendszerint bájtonként tároljuk a karaktereit; a bájt legfelső bitje ekkor 0.
Nyelvfüggő kódlapok
Az ékezetes betűk és további jelek tárolásához különböző 8 bites kódlapok terjedtek el. Ezek egy bájton legfeljebb 256 különböző kódértéket tudnak megkülönböztetni. A következő kódlapok alsó 128 kódértéke az ASCII-val egyezik meg, a további kódértékek jelentése viszont eltérhet.
| Kódlap | Jellemző felhasználás |
|---|---|
| IBM CP852 | Régi DOS-os, közép-európai szövegek; a magyar ékezetes betűket is tartalmazza. |
| Windows-1250 | Régebbi Windowsos, közép-európai szövegek. |
| ISO-8859-1 (Latin-1) | Elsősorban nyugat-európai nyelvek; az ő és az ű nincs benne. |
| ISO-8859-2 (Latin-2) | Közép- és kelet-európai nyelvek; a magyar ékezetes betűket is tartalmazza. |
Ezek különböző kódlapok, nem ugyanannak a kódolásnak a nevei. Ugyanaz a bájt az egyik kódlap szerint más karaktert jelenthet, mint egy másik szerint.
A programokban előforduló ANSI megnevezés nem egyetlen, egyértelműen meghatározott karakterkódolás neve. Windowsos környezetben többféle régi kódlapra is utalhat. Adatcserénél ezért célszerű pontos nevet megadni, például Windows-1250.
Unicode: közös karakterkészlet
A nyelvenként eltérő kódlapok megnehezítették a többnyelvű szövegek kezelését. A Unicode célja, hogy közös rendszerben lehessen azonosítani a különböző írásrendszerek karaktereit, valamint a matematikai, műszaki és egyéb jeleket.
A Unicode sok mai és történeti írásrendszer jeleit tartalmazza, és folyamatosan bővül. Karakterkészletét és kódpontjait az ISO/IEC 10646 szabvánnyal összehangoltan határozzák meg. A Unicode emellett a szövegkezeléshez szükséges további szabályokat is leír.
| Karakter | Unicode-kódpont | Jelentés |
|---|---|---|
| A | U+0041 | Latin nagy A betű |
| ó | U+00F3 | Latin kis o betű éles ékezettel |
| ő | U+0151 | Latin kis o betű kettős éles ékezettel |
| ° | U+00B0 | Fokjel |
| Ω | U+03A9 | Görög nagy ómega |
| € | U+20AC | Eurójel |
A Unicode első 128 kódpontja, az U+0000–U+007F tartomány, az ASCII kódjainak felel meg.
A kódpont azonosítja a karaktert, de önmagában nem mondja meg, milyen bájtsorozat kerüljön a fájlba. Ehhez konkrét kódolásra van szükség, például UTF-8-ra vagy UTF-16-ra.
Kiegészítés: A Unicode kódponttartománya U+0000–U+10FFFF. Az első, U+0000–U+FFFF közötti síkot BMP-nek (Basic Multilingual Plane) nevezzük. Nem minden kódponthoz tartozik karakter; egyes tartományok különleges célra vannak fenntartva.
UTF-8 kódolás
Az UTF-8 a Unicode-karakterek bájtokkal történő ábrázolásának egyik módja. Változó hosszúságú kódolás: egy kódolható Unicode-kódponthoz 1, 2, 3 vagy 4 bájtot rendel.
Fontos tulajdonságai:
- Az ASCII-karaktereket változatlan kóddal, egy bájton tárolja.
- A magyar ékezetes betűk szokásos, önálló kódponttal megadott alakja két bájtot foglal.
- Sok további jel, például az eurójel, három bájtot igényel.
- Egyes további karakterek, például számos emoji alapkaraktere, négy bájtot igényelnek.
| Karakter | Unicode-kódpont | UTF-8-bájtok hexadecimálisan | Hossz |
|---|---|---|---|
| A | U+0041 | 41 | 1 bájt |
| ó | U+00F3 | C3 B3 | 2 bájt |
| ő | U+0151 | C5 91 | 2 bájt |
| Ω | U+03A9 | CE A9 | 2 bájt |
| € | U+20AC | E2 82 AC | 3 bájt |
Példa: a mérő szó négy betűből áll, de UTF-8-ban hat bájtot foglal:
Karakter: m é r ő UTF-8 (hex): 6D C3 A9 72 C5 91 Bájtok száma: 1 + 2 + 1 + 2 = 6
Ebben a számításban nincs sortörés vagy más kiegészítő jel a szöveg végén, és nincs BOM a fájl elején.
Megjegyzés: Egy képernyőn egyetlen jelként látható elem több Unicode-kódpontból is állhat. Például egy ékezetes betű leírható alapbetű és külön ékezet kombinációjával is. Ezért a látható jelek, a kódpontok és a bájtok száma három különböző mennyiség lehet.
Az UTF-8 bitmintái – kiegészítő magyarázat
Az UTF-8 bájtjainak elején található bitek jelzik a bájt szerepét. Az alábbi táblázatban az x helyekre a kódpont értékének bitjei kerülnek:
| Teljes hossz | A bájtok bitmintája |
|---|---|
| 1 bájt | 0xxxxxxx |
| 2 bájt | 110xxxxx 10xxxxxx |
| 3 bájt | 1110xxxx 10xxxxxx 10xxxxxx |
| 4 bájt | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
Többbájtos kódolás esetén az első bájt elején álló 1-esek száma a teljes bájtsorozat hosszát jelzi. A további, úgynevezett folytató bájtok mindig 10 bitekkel kezdődnek.
Az egyes kódpontokat a legrövidebb megengedett alakban kell kódolni. A táblázat szerkezeti vázlat: nem minden lehetséges x-kitöltés alkot érvényes UTF-8-sorozatot.
Az ó betű kódolása
Az ó Unicode-kódpontja U+00F3, amely decimálisan 243, binárisan 11110011.
Ez nem fér el a 7 bites ASCII-tartományban, ezért kétbájtos UTF-8-alak szükséges. A kétbájtos minta 5 + 6, összesen 11 adatbitnek biztosít helyet. A kódpont bináris alakját balról nullákkal 11 bitre egészítjük ki:
Kódpont 11 biten: 00011110011
Felbontás 5 + 6 bitre: 00011 110011
UTF-8-minta: 110xxxxx 10xxxxxx
Adatbitek behelyettesítése:
11000011 10110011
Hexadecimálisan: C3 B3
Az ó betű UTF-8-kódja tehát a C3 B3 bájtsorozat.
UTF-16 és BOM – rövid kitekintés
Az UTF-16 szintén Unicode-kódolás. Egy kódolható Unicode-kódpontot egy vagy két 16 bites egységgel, vagyis 2 vagy 4 bájttal ábrázol. A magyar betűk szokásos, önálló kódponttal megadott alakja két bájtot foglal.
Mivel egy 16 bites egység két bájtból áll, meg kell határozni e bájtok sorrendjét:
- Big-endian: a nagyobb helyi értékű bájt kerül előre.
- Little-endian: a kisebb helyi értékű bájt kerül előre.
Például az A kódpontja U+0041. UTF-16BE esetén bájtjai 00 41, UTF-16LE esetén 41 00.
A fájl elején elhelyezett BOM (Byte Order Mark) segíthet a kódolás és a bájtsorrend felismerésében. A BOM a U+FEFF speciális kezdő jel kódolt alakja:
| Kódolás | BOM-bájtok hexadecimálisan |
|---|---|
| UTF-16, big-endian bájtsorrend | FE FF |
| UTF-16, little-endian bájtsorrend | FF FE |
| UTF-8 | EF BB BF |
A BOM nem minden esetben kötelező. A bájtsorrendet például a formátum vagy egy külön kódolásmegjelölés is meghatározhatja. UTF-8 esetén nincs bájtsorrend-választás: a BOM ott csak a kódolásra utaló jelzés lehet. A BOM-ot a szövegszerkesztők rendszerint nem jelenítik meg közönséges karakterként.
Gyakorlati karakterkódolási problémák
Miért romlanak el az ékezetek?
Ha a fájl UTF-8-ban készült, de az olvasó program más kódlap szerint értelmezi a bájtjait, hibás szöveg jelenhet meg.
Például az ó UTF-8-bájtjai C3 B3. Ha ezt a két bájtot Windows-1252 szerint, két külön karakterként olvassuk, az eredmény ó lesz.
A fájlban lévő bájtok ekkor még lehetnek helyesek; a program rossz szabály szerint értelmezi őket.
Egy szövegfájl kódolása nem mindig állapítható meg biztosan pusztán a tartalmából. A .txt vagy .csv kiterjesztés önmagában nem határozza meg a karakterkódolást.
Mit tegyünk hibásan megjelenő szöveg esetén?
- Őrizzük meg az eredeti fájlt.
- Ellenőrizzük, milyen kódolással exportálták vagy mentették.
- A megnyitó programban válasszuk ki a megfelelő kódolást.
- Csak a helyesen megjelenő szöveget alakítsuk át más kódolásra, ha ez szükséges.
A más kódolással történő megnyitás és az átkódolás nem ugyanaz. Megnyitáskor a meglévő bájtokat értelmezzük; átkódoláskor a felismert karakterekhez új bájtsorozatot hozunk létre.
Ha például Unicode-szöveget olyan régi kódlapra mentünk, amely nem tartalmaz minden szükséges jelet, információvesztés történhet. A hiányzó jelek helyére kérdőjel vagy helyettesítő karakter kerülhet. Ez utólag pusztán a kódolás átállításával már nem feltétlenül javítható.
Karakterkódolás vagy betűtípushiba?
A karakterkódolás azt határozza meg, hogyan értelmezzük a bájtokat. A betűtípus azt határozza meg, hogyan rajzoljuk ki a karaktereket.
Ha értelmetlen betűsorok jelennek meg az ékezetek helyén, gyakran kódolási hiba történt. Ha egy jel helyén üres négyzet látható, előfordulhat, hogy a használt betűtípus nem tartalmazza az adott jel rajzolatát. A két problémát eltérően kell kezelni.
Mérnöki adatcsere
Mérési adatokat tartalmazó CSV-fájlnál külön kell megadni vagy ellenőrizni:
- a karakterkódolást, például UTF-8;
- az oszlopelválasztót, például pontosvessző vagy vessző;
- a tizedesjelet, például vessző vagy pont.
Ezek különböző beállítások. A helyes kódolás önmagában nem oldja meg a rosszul felismert oszlopelválasztó problémáját.
Például egy műszer Hőmérséklet [°C] nevű oszlopának megnyitásakor az ékezetekhez és a fokjelhez megfelelő karakterkódolás szükséges.
Új szöveges adatcsere kialakításakor célszerű az UTF-8-at választani, amennyiben a részt vevő rendszerek támogatják. A kódolást az adatcsere leírásában is rögzíteni kell.
Számjegy és szám
A szövegben szereplő számjegyek szintén karakterek. A 123 szöveg ASCII-ban és UTF-8-ban három bájt:
Karakterek: 1 2 3 Bájtok hexadecimálisan: 31 32 33
A 123 számérték tárolása ettől eltérhet. Például egy előjel nélküli 8 bites egész számként egyetlen bájtban, 01111011 bitmintával tárolható. A szöveges és a numerikus ábrázolást ezért meg kell különböztetni.
Base64 – bináris adatok szöveges ábrázolása
A Base64 nem karakterkódolás az ASCII vagy az UTF-8 értelmében. Feladata, hogy egy tetszőleges bájtsorozatot korlátozott készletből választott, nyomtatható karakterek sorozataként ábrázoljon.
Így például kép, tömörített fájl vagy más bináris adat is továbbítható olyan környezetben, amely szöveges adatot vár. Ismert alkalmazása az e-mail-mellékletek átvitele. A levelezésben használt MIME kiterjesztések egyik átviteli kódolása a Base64. Történetileg ezt a megoldást a levelezőrendszerek 7 bites korlátai is indokolták.
A Base64 nem titkosítás: az eredeti adat titkos kulcs nélkül visszaállítható. Nem is tömörítés: a kódolt adat általában nagyobb lesz az eredetinél.
A kódolás elve
A Base64 a bemeneti adat bitjeit 6 bites csoportokra osztja. Hat bit 64 különböző értéket vehet fel, ezért 64 különböző adatjelre van szükség:
| Érték | Hozzárendelt karakterek |
|---|---|
| 0–25 | A–Z |
| 26–51 | a–z |
| 52–61 | 0–9 |
| 62 | + |
| 63 | / |
A kódolás 3 bemeneti bájtból 4 kimeneti karaktert állít elő, mert 3 × 8 = 4 × 6 = 24 bit. A végén szükség esetén külön kitöltő jel, az = is megjelenik. Ez nem tartozik a 64 adatjelhez.
Példa: Man
Kódoljuk a Man szöveg ASCII-bájtjait! Ezek UTF-8 esetén is ugyanazok.
Karakterek: M a n ASCII-bájtok: 01001101 01100001 01101110 6 bites csoportok: 010011 010110 000101 101110 Decimális értékek: 19 22 5 46 Base64-jelek: T W F u
Az eredmény tehát TWFu.
Mi történik, ha nem teljes a három bájtos csoport?
A bemenet bájtokból áll, de a bájtok száma nem mindig osztható hárommal. Az utolsó 6 bites adatcsoportot ilyenkor jobbról nulla bitekkel egészítjük ki, a hiányzó kimeneti karakterek helyére pedig = jeleket írunk.
| Az utolsó csoport bemenete | Kimeneti adatjelek száma | Kitöltés |
|---|---|---|
| 3 bájt | 4 | Nincs |
| 2 bájt | 3 | Egy = jel |
| 1 bájt | 2 | Két = jel |
Egybájtos példa: kódoljuk a 00000001 bájtot!
Bemenet: 00000001
6 bites csoportok: 000000 01
Nullákkal kiegészítve:
000000 010000
Értékek: 0 16
Adatjelek: A Q
Kitöltéssel: AQ==
Kétbájtos példa: kódoljuk a 00000010 00000001 bájtokat!
Bemenet: 00000010 00000001
6 bites csoportok: 000000 100000 0001
Nullákkal kiegészítve:
000000 100000 000100
Értékek: 0 32 4
Adatjelek: A g E
Kitöltéssel: AgE=
Dekódoláskor az adatjeleket visszaalakítjuk 6 bites értékekké, majd visszaállítjuk az eredeti bájtokat. Két = esetén az utolsó két adatjel 12 bitjéből csak 8 adatbit; a maradék 4 kitöltő nulla. Egy = esetén az utolsó három adatjel 18 bitjéből 16 adatbit; a maradék 2 kitöltő nulla.
Méretnövekedés és gyakorlati megjegyzések
Három bemeneti bájtból négy ASCII-karakter, azaz szöveges tároláskor négy bájt lesz. A méretnövekedés ezért nagyobb adatoknál körülbelül 33%. Kis adatoknál a kitöltés miatt az arány nagyobb is lehet.
Például 300 bájt adat Base64-alakja 400 karakterből áll, a sortörések és más kiegészítő adatok nélkül.
A MIME szerinti Base64-szöveg sorokra tördelhető. Más alkalmazások viszont egyetlen összefüggő karaktersorozatot várhatnak. A sortörések és egyéb idegen karakterek elfogadása ezért az alkalmazás szabályaitól függ; nem feltételezhetjük, hogy minden Base64-dekódoló figyelmen kívül hagyja őket.
Ha szöveget szeretnénk Base64-kódolni, előbb meg kell határozni annak bájtjait, például UTF-8 használatával. A Base64 önmagában nem őrzi meg, milyen karakterkódolással készült a bemeneti szöveg.
Ellenőrző kérdések
- Miért nem ábrázolható az
őbetű ASCII-val? - Mi a különbség a Unicode-kódpont és az UTF-8-bájtsorozat között?
- Hány bájt a
mérőszó UTF-8-ban, ha a betűk a szokásos önálló kódpontjaikkal szerepelnek, és nincs BOM vagy sortörés? - Mit érdemes először ellenőrizni, ha egy CSV-fájlban elromlanak az ékezetek?
- Mi a különbség egy fájl más kódolással történő megnyitása és átkódolása között?
- Titkos adatnak tekinthető-e egy Base64-kódolt jelszó? Indokolja a választ!
- Hány karakterből áll 300 bájt adat Base64-alakja, sortörések nélkül?
Rövid megoldások
- Az ASCII karakterkészlete nem tartalmazza az
őbetűt. - A kódpont a karakter azonosítója; az UTF-8-bájtsorozat annak konkrét tárolási alakja.
- Hat bájt: 1 + 2 + 1 + 2.
- Azt, hogy a megnyitó program a fájl eredeti karakterkódolását használja-e.
- Megnyitáskor a meglévő bájtokat értelmezzük; átkódoláskor új bájtsorozatot hozunk létre.
- Nem. A Base64 kulcs nélkül visszaalakítható, és nem biztosít titkosságot.
- Négyszáz karakterből.
