Bevezetés a Karakterkódolásba

UTF-16

az UTF-16 egy 16 bites változó hosszúságú kódolási séma, amely az UTF karakterkészletet használja a karakterkód pontokhoz. Ez azt jelenti, hogy egy UTF-16 kódolt karakter 16 bites kódegységgel rendelkezik.

mivel tudjuk, hogy egy UTF-8 kódolt karakter 1-4 kódegységben ábrázolható, az UTF-16 karakter 1 vagy 2 kódegységben ábrázolható. Ezért egy UTF-16 karakter 16 vagy 32 bit memóriát vehet igénybe a kódpontja alapján.

mielőtt beleugranánk az UTF-16 kódolási specifikációkba, értsük meg, hogyan tudjuk az UTF-16 működését.

mivel 16 bites kódegységgel rendelkezünk, elméletileg 21-et tudunk kódolni a 0 kódponttól a 65 535-ig. De mi van, ha van egy karakterünk, amelynek kódpontja nagyobb, mint 65 535? Ebben az esetben hozzáadhatunk egy másik kódegységet.

Az extra kódegységgel összesen 232 karaktert kódolhatunk, ami több mint 4M. de akkor a kérdés az, hogy egy UTF-16 dekóder honnan tudja, hogy 2 kódegységet kell figyelembe vennie egy karakter dekódolásához?

az UTF-8 úgy oldotta meg ezt a problémát, hogy az első kódegység kezdeti bitjeit és a folytató kódegységeket bizonyos bitértékekre állította, amelyeket az UTF-8 dekóder használhat arra, hogy levonja, hány kódegységet vehet fel egy karakter.

ugyanezt megtehetjük az UTF-16 kódegységgel is, de akkor fel kell áldoznunk néhány bitet egy kódegységben ehhez a funkcióhoz. Beállíthatjuk a kódegység néhány kezdeti bitjét valamilyen értelmes értékre, amelyet egy UTF-16 dekóder megérthet.

ahhoz, hogy önszinkronizáló erőt adjon a kódegységeknek, a kódegységnek meg kell tudnia mondani, hogy ez a kezdeti kódegység vagy a folytató kódegység, és nem csak egy kódegység karaktere.

tehát az Unicode úgy döntött, hogy feláldozza a kódegység kezdeti 6 bitjét, így csak 10 bit marad a kódegység kódpontjának kódolására. Ha egy karakternek 2 kódegységre van szüksége, akkor a memória 20 bitje (32 bitből vagy 4 bájtból) tartalmazza a karakter tényleges kódpont-információit.

tehát mik ezek a kezdeti bitek, és hogyan hatnak ezek a bitek az UTF karakterkészletbe? Kövessük az alábbi példát.

1101 10xx xxxx xxxx 1101 11xx xxxx xxxx
FIRST CODE UNIT---- SECOND CODE UNIT---

az UTF-16 szabvány szerint az első kódegységnek 110110₂-val, a második kódegységnek pedig 110111₂-val kell kezdődnie. Ez segít az UTF-16 dekódernek megérteni, hogy melyik az első kódegység, és melyik a második. Ez teszi az UTF-16 önszinkronizálását.

most mi van 10 bit kódegységenként játszani, mi a tartomány tudunk játszani belül? Végül hány karaktert lehet kódolni az UTF-16 kódolás két kódegységében?

ne aggódjon, csak egy kódegységben kódolt karakterekről fogunk beszélni.

ha megnézi a fenti kódegység sablonokat, akkor az 1101 1000 0000 0000-1101 1111 11111-ig terjedő tartományunk van. Ez ekvivalens a D800i-GI-vel a DFFFI-GI-vel.

az első kódegység tartománya D800jg-től 6FFFJG-ig, a második kódegység tartománya pedig DC00JG-től DFFFJG-ig terjed. Ezeket az értékeket az összes kódpont Bit be-és kikapcsolásával kaphatjuk meg.

mivel az UTF-16-nak önszinkronizálónak kell lennie, a d800i és DFFFI-gi közötti Kódpontok nem képviselhetnek karaktert az UTF-16-ban. Mivel minden UTF kódolás ugyanazt az UTF karakterkészletet követi, ezeket a kódpontokat az UTF korlátozza, és nem rendelhetők hozzá semmilyen karakterhez.

a D800i-GI és a DFFFI-gi közötti Kódpontok nem jelentenek semmilyen karaktert, ezért helyettesítő kódpontoknak nevezzük őket, vagy együtt helyettesítő pároknak is nevezzük őket.

az első helyettesítő kódpont (az első kódegységből) magas helyettesítőnek, a második kódpontnak (a második kódegységből) pedig alacsony helyettesítőnek is nevezik. Összesen 2048 kódpont, 1024 helyettesítőnként.

a helyettesítő Kódpontok feláldozták az életüket, hogy több karaktert kódolhassunk két kódegységgel. Gondolj bele!

tehát a nagy kérdés, hogy kódolhatunk-e egy karaktert egyetlen UTF-16 kódegységgel? A válasz igen. Az UTF-16 egy 16 bites változó hosszúságú kódolási séma. Tehát ez azt jelenti, hogy 21 am karaktert kódolhatunk egyetlen kódegységgel?

a válasz nem. Elméletben kódolhatnánk 21 as karaktert a 0000jpt (0jpt) kódponttal FFFFJPT (65535jpt) – re, de a d800jpt és DFFJPT közötti Kódpontok nem jelentenek semmilyen karaktert, mivel fenn vannak tartva.

ezért biztonságos kódolni a karaktereket 0000jp-től D7FFJP-ig és E000jp-től FFFFJP-ig, így 63 488 (65536-2048) karakterig. Ez csak azokra a karakterekre vonatkozik, amelyeket az UTF-16 egyetlen kódegységében lehet kódolni.

mivel összesen 20 bitet kell játszanunk, amikor a karakterekről van szó, mint amennyit az UTF-16 2 kódegységébe lehet kódolni, 22oritmus több karaktert kódolhatunk, ami 1 048 576 karakter.

tehát összesen 1 048 576 + 63 488 kódot tudunk kódolni, ami 1 112 064 karakter (több mint 1 millió karakter). Ez az UTF karakterkészlet határa. Mivel az UTF-16 képes kódolni ezeket a sok karaktert, más UTF kódolások nem képviselhetnek ezeken túlmutató karaktereket.

UTF karakterkészlet-Kódpontok

mivel tudjuk, hogy a kódpont egy karakterhez rendelt tizedes érték, mi (Unicode) nem rendelhetünk érvénytelen kódpontot egy tényleges karakterhez. Eddig Az érvénytelen Kódpontok helyettesítő Kódpontok.

egyetlen UTF-16 kódegységgel 63 488 karaktert tudunk kódolni 0000-től d7ffi-ig és E000i-tól FFFFI-ig. Az utolsó kódpont 65,535. Ezeket BMP karaktereknek nevezzük (később elmagyarázzuk).

két UTF-16 kódegységgel 1 048 576 karaktert tudunk kódolni. Mivel nem tudjuk újra indul 0 érték (kódpont) mert ezek után jönnek BMP karakterek, meg kell ellensúlyozni őket 65,536. Ezeket a karaktereket kiegészítő karaktereknek nevezzük (később elmagyarázzuk).

ezért az első kiegészítő karakter kódpontértéke 65536licc, amely egyenértékű 10000lickerrel. Mivel 1 048 576 karaktert kódolhatunk két UTF-16 kódegységgel, az utolsó kódpont az 1114111LICC, amely egyenértékű a 10FFFFI-vel.

tehát bontsuk le a dolgokat egyszerű táblázatos formában.

+-----------+---------------------+--------------------+
| UTF-16 CU | Code Point | |
+-----------+---------------------+--------------------+
| 1 | 0000₁₆ - D7FF₁₆ | valid |
+-----------+---------------------+--------------------+
| 1 | D800₁₆ - DFFF₁₆ | invalid(surrogate) |
+-----------+---------------------+--------------------+
| 1 | E000₁₆ - FFFF₁₆ | valid |
+-----------+---------------------+--------------------+
| 2 | 10000₁₆ - 10FFFF₁₆ | valid |
+-----------+---------------------+--------------------+
| | 110000₁₆ - FFFFFF₁₆ | unassigned |
+-----------+---------------------+--------------------+

ezzel a tudással nézzük meg, hogyan kódolhatunk néhány karaktert az UTF-16-ban. Válasszunk egy egyszerű ASCII karaktert a (kódpont: 41ifornic), egy karaktert a hindi (Indiai) nyelvből (ejtsd: Aa, kódpont: 906ifornic), és egy Emoticon A-t (Happy face, kódpont: 1f60aifornic).

mint a fenti táblázatból láthatjuk, mind az a, mind a 6 kódolható az UTF-16 egyetlen kódegységébe, mivel értékeik kisebbek, mint FFFFJGVERI.

Ha egy karaktert csak egy kódegységben kell kódolnunk, akkor csak a karakter kódpontját kell konvertálnunk egy 16 bites bináris számba. Az a karakterek esetében a 00000000 01000001₂ az UTF-16 ábrázolás.

Hasonlóképpen, a karakterek esetében a 906iforg kódpontját csak 16 bites bináris számra kell konvertálni, amely 00001001 00000110₂.

általában egy karakter kódegységeit ábrázoljuk hexadecimális számokban. Ezért az a karakter esetében az UTF-16 reprezentáció 0041i-t, míg a karakter esetében az UTF-16 reprezentáció 0906i-t.

a karakterek esetében a dolgok kissé eltérnek. A kódpont az 1F60AIY. Ha megnézzük a fent említett UTF-16 táblázatot, akkor azt az UTF-16 2 kódegységébe kell kódolni. Szóval hogyan kezdjük?

először ki kell vonnunk a kódpontból 10000-et. Ennek oka az, hogy az UTF-16 2 kódegységében kódolt minden karakter a BMP karakterek után jött, amelyek Utolsó kódpontja az FFFFJGARI.

ezért ahhoz, hogy megkapjuk a kódoláshoz használt bitek tényleges értékét (ami 20 a 2 kódegységben), ki kell vonnunk a kódpontból 10000jgv-t, és a végső számot kell használnunk a 20 bit előállításához.

a jobb megértés érdekében az UTF-16 2 kódegységével ábrázolt első karakternek mind a 20 bitje 0 lesz. Tehát a karakter kódpontjának kódolásához használt bitek értéke 0. De még mindig, a kódpont 10000ifornia szerint Unicode karakterkészlet. Ennek oka az, hogy az e 20 Bit által kapott értéket hozzáadjuk az 10000iforgar-hoz, hogy létrehozzuk a végső kódpontot.

mint korábban láttuk, ez a 2 kódegység az alábbiak szerint néz ki.

1101 10xx xxxx xxxx 1101 11xx xxxx xxxx
FIRST CODE UNIT---- SECOND CODE UNIT---

csak ki kell töltenünk ezt a 20 bitet (x) a karakterkód ponttól kapott értékkel. A kódpont a karakter 60a5peri. De először ki kell vonnunk belőle az 10000ifort. Megkapjuk az F60AIY-t.

most át kell alakítanunk az F60A9PERIT egy 20 bites bináris számra, és ki kell töltenünk a fenti kódegység sablon 20 bitjét. A binárisan F60AIPULIN értéke 0000111101 1000001010₂. Most kitölthetjük ezt a 20 helyőrző bitet.

Az alábbiakban a végső kódegységek találhatók.

1101 1000 0011 1101 1101 1110 0000 1010
0xD83D 0xDE0A

a gyors módja annak, hogy ellenőrizze, hogy ezek a kódegységek érvényesek-e, és valóban ezek a helyettesítő párok képesek-e képviselni a kódolt karaktert, nyisson meg egy böngésző DevTool-ot, és írja be a console.log('\uD83D\uDE0A'); a konzolba.

(Chrome fejlesztői eszközök)

ezt az online eszközt UTF-16 Kódpontok létrehozására is használhatja.

Unicode Karaktersíkok

a sík 21A vagy 65 536 kódpont folytonos csoportja. Mivel az UTF-16 a kódpontokat legfeljebb 10ffffi-ig korlátozta, az Unicode szabványban összesen 17 karakteres sík van 0-tól 16-ig.

mivel 21 Al karakter definiálható az UTF-16 egyetlen kódegységével (beleértve a helyettesítő kódpontokat is), ez képezi az első (0.) síkot. Ez a sík szinte az összes karaktert tartalmazza az alapnyelveken szerte a világon. Ezért hívják ezt a síkot alapvető többnyelvű síknak vagy BMP-nek.

ezután az UTF-16 két kódegysége által meghatározott Kódpontok vannak. Ezek 22try karaktereket tartalmaznak, mivel 20 bitünk van a kódpont értékének kódolására. Ezeket 16 síkra osztják (2 x 21 in). Ezeket kiegészítő síkoknak nevezzük.

a síkokkal kapcsolatos további információkért olvassa el ezt a Wikipedia dokumentumot.

összehasonlítás az UCS-2-vel

az UCS-2 egy 16 bites fix szélességű kódolás. Ez azt jelenti, hogy csak egy 16 bites kódegységet használnak egy kódpont ábrázolására. Elméletileg az UCS – 2 21 különálló karaktert képviselhet, de van egy csavar.

btw, a kódegység kifejezést használjuk ebben a fix szélességű kódolásban, hogy megértsük az UTF-16 közötti kapcsolatot. A valóságban nincs olyan dolog, mint kód egység minden rögzített kódolás.

mivel az UCS az Unicode karakterkészletet követi, az UCS-2 karaktereinek kódolása megegyezik az UTF-16 karaktereinek kódolásával, amelyek csak egy kódegységben vannak ábrázolva.

mivel az UCS az Unicode karakterkészletet követi, nem tud érvényes karaktert kódolni a helyettesítők számára fenntartott kódpontokkal.

tehát dióhéjban az UCS-2 tartalmazza az alapvető többnyelvű sík karaktereit. Ez az oka annak, hogy néhány régebbi dokumentum és szoftver UCS-2 kódolást használt. De az UCS-2 kódolás elavulttá vált, és az UTF-16-ot részesítik előnyben.

Endianness és BOM

ahogy korábban tárgyaltuk, az UTF kódolt dokumentumok alacsony szinten tartalmazzák a kódegységek sorrendjét. Az UTF-8 esetében a kódegység 8 Bit hosszú, míg az UTF-16 esetében 16 bit hosszú. Ezek a kódegységek alkotják a karaktereket.

egy UTF-8 vagy UTF-16 dekóder egymás után olvassa be a kódegységeket, egyszerre egy kódegységet a karakterek előállításához.

minden kódegység egy numerikus értéket képvisel, amelyet egy UTF-8 vagy UTF-16 dekóder megvizsgálhat, és eldöntheti, hogy elegendő-e egy karakter ábrázolása, vagy más kódegységeket követ, amelyeket szintén figyelembe kell venni.

amikor az UTF-8-ról van szó, a dolgok egyszerűek. Mivel minden kódegység 8 Bit hosszú, a 8 bites bináris szám numerikus értékre konvertálása gyors és egyszerű. Az UTF-16 esetében azonban nem ez a helyzet.

az UTF-16 kódegység egy 16 bites (2 bájtos) bináris szám, amely egy kódpont értéket képvisel. A numerikus érték több bájtból történő generálása általában bonyolult, és a különböző rendszerek eltérően viselkednek.

Ez a viselkedés a rendszer végességétől függ. Az endiannessről szóló korábbi beszélgetésünk alapján kétféle módon írhatunk UTF-16 kód egységértéket. Vagy Big-endian formátumban, vagy Little-endian formátumban.

Big-endian formátumban az MSB tárolódik először, az LSB pedig utoljára. Eddig az UTF-16 kódegység értékét írjuk Big-endian formátumban. Az UTF-16 kód egységértékének Little-endian-ban történő írásához bájtot kell cserélnünk.

beszéljünk a karakterről. A korábbi példából az UTF-16 egyetlen kódegységében ábrázolható, a hexadecimális ábrázolásban történő kódolása pedig 0906spektíva.

a 0906spektíva egy 16 bites szám, ahol a 09 az MSB, a 06 pedig az LSB. Ezért a Big-endian architektúrában 09 06-ként lesz tárolva. A Little-endian architektúrában azonban 06 09-ként tárolják.

ezért a mi felelősségünk a karakterek kódolása, figyelembe véve a rendszer endianitását, hogy a rendszer helyesen tudja olvasni az UTF-16 dokumentumot.

de hogyan tudjuk előre megmondani, hogy a Felhasználó gépe kompatibilis-e a kódolt dokumentummal vagy sem? És mivel egy rendszer végletessége befolyásolhatja egy dokumentum dekódolását, hogyan osztjuk meg nyilvánosan?

itt jön a képbe a BOM. A Byte Order Mark (BOM) egy bájtsorozat, amelyet a szövegfájl vagy a szöveges adatok elején adnak hozzá.

a Unicode a feffliurger kódpontú karaktert ajánlja az UTF-16 és UTF-32 kódolások BOM-jaként. Ennek a karakternek a dokumentum első karaktere előtt kell lennie. Ezt a karaktert azonban a dekóder nem veszi figyelembe a kimeneten.

Ez a karakter (U+FEFF) egy nulla szélességű, nem törő tér (ZWNBSP) karakter, és láthatatlan. Ezért még akkor is, ha a dekóder nem ismeri fel a BOM-ot, nem fog látható kimenetet produkálni.

Ez a karakter az UTF-16 egyetlen kódegységében jelenik meg, hexadecimális ábrázolásban pedig FE (MSB) és FF (LSB).

ezért, ha a karaktereket Big-endian formátumban kódoljuk, a fájl elején hozzá kell adnunk a FEFF-et BOM-ként, ha pedig a karaktereket Little-endian formátumban kódoljuk, akkor a fájl elején hozzá kell adnunk az fffe-t (fordított) BOM-ként.

az Unicode javasolja a BOM hozzáadását az UTF-16 kódolású dokumentumhoz. Ha azonban hiányzik a BOM, akkor feltételezzük a Big-endian formátumot.

az IANA az UTF-16 azonosítót részesíti előnyben az UTF-16 kódolású dokumentum jelölésére. Az UTF-16BE-t azonban a Big-endian formátumban kódolt dokumentumokhoz, az UTF-16le-t pedig a Little-endian formátumhoz használják.

ha UTF-16BE vagy UTF-16LE nevet használ, akkor a BOM nem ajánlott a fájl elé írni. Még ebben az esetben is, ha a BOM hozzáadódik, akkor azt ZWNBSP karakternek tekintik, és nem fogják figyelmen kívül hagyni.

az UTF-16, utf-16BE és UTF-16le nevek kisbetűk érzéketlenek.

előnyök és hátrányok

az UTF-16 azért hatékony, mert csak 2 kódegységgel rendelkezik, és mivel a legtöbb használt karakter a BMP készletbe tartozik, csak egy kódegységben ábrázolható. Ez azonban sok kérdéssel jár.

az UTF-16 legnagyobb hátránya, hogy nem ASCII kompatibilis. Mivel az ASCII karakterek egyetlen kódegységgel vannak kódolva (16 bites szám), ezeket nem lehet megfelelően dekódolni egy ASCII dekóderrel.

az UTF-16 felesleges helyet foglal el az ASCII karakterek számára. Az UTF-8 kódolású dokumentumhoz képest, amely csak ASCII karaktereket tartalmaz, az UTF-16-ban kódolt dokumentum mérete kétszer nagyobb.

UTF-16 is hatással lesz a endianness a rendszer. Ha hiányzik a BOM, és nincs megfelelő kódolási azonosító (például UTF-16LE), akkor előfordulhat, hogy az UTF-16 kódolású dokumentum nem lesz megfelelően dekódolva.

az UTF-16 kódolás jellege miatt olyan helyettesítő kódpontokat vezetett be, amelyek nem tudják képviselni az érvényes karaktereket. Ezenkívül korlátozta az Unicode karakterkészletet 10FFFFI-re (utolsó kódpont).

ezen tények ellenére néhány programozási nyelv, például JavaScript, Java stb. az olyan rendszerek, mint a Windows, az UTF-16 kódolást részesítik előnyben.

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.