Johdatus Merkistökoodaukseen

UTF-16

UTF-16 on 16-bittinen muuttuvapituinen koodausjärjestelmä ja se käyttää UTF-merkistöä merkistökoodin pisteille. Tämä tarkoittaa, että UTF-16 koodatulla merkillä on 16-bittinen koodiyksikkö.

koska tiedämme, että UTF-8 koodattu merkki voidaan esittää 1-4 koodiyksikössä, UTF-16-merkki voidaan esittää 1 tai 2 koodiyksikössä. Näin ollen UTF-16-merkki voi ottaa 16 tai 32 bittiä muistia koodipisteensä perusteella.

ennen kuin hypätään UTF-16-koodausmäärityksiin, selvitetään, miten saamme UTF-16: n toimimaan.

koska meillä on 16-bittinen koodiyksikkö, voimme teoriassa koodata 21⁶ merkkiä koodipisteestä 0-65,535. Mutta entä jos meillä on merkki, jonka koodipiste on suurempi kuin 65 535? Siinä tapauksessa voimme lisätä toisen koodiyksikön.

ylimääräisellä koodiyksiköllä voimme koodata yhteensä 232 merkkiä, mikä on yli 4M. mutta sitten kysymys on, miten UTF-16-koodaaja tietää, että sen on otettava huomioon 2 koodiyksikköä purkaakseen merkin?

UTF-8 ratkaisi tämän ongelman asettamalla ensimmäisen koodiyksikön alkubitit ja jatkokoodiyksiköt tietyille bittiarvoille, joiden avulla UTF-8-dekooderi voi vähentää, kuinka monta koodiyksikköä merkki voi kestää.

voimme tehdä saman UTF-16-koodiyksikölle, mutta sitten joudumme uhraamaan joitakin bittejä koodiyksikössä tämän ominaisuuden vuoksi. Voimme asettaa joitakin koodiyksikön alkubittejä johonkin merkitykselliseen arvoon, jonka UTF-16-dekooderi voi ymmärtää.

myös antaakseen itsesynkronointitehoa koodiyksiköille, koodiyksikön on kyettävä kertomaan, onko kyseessä alkukoodiyksikkö vai jatkokoodiyksikkö eikä vain yhden koodiyksikön merkki.

Niinpä Unicode päätti uhrata koodiyksikön ensimmäiset 6 bittiä jättäen vain 10 bittiä koodaamaan merkin koodipisteen koodiyksikköä kohti. Jos merkki tarvitsee 2 koodiyksikköä, 20 bittiä muistista (32 bitistä tai 4 tavusta) sisältää merkin varsinaiset koodipistetiedot.

joten mitä nämä alkubitit ovat ja miten nämä bitit tekevät lommon UTF-merkistössä? Seurataan alla olevaa esimerkkiä.

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

UTF-16-standardista ensimmäisen koodiyksikön tulee alkaa 110110 ja toisen koodiyksikön tulee aloittaa 110111 ICS: llä. Tämä auttaa UTF-16-dekooderia ymmärtämään, kumpi on ensimmäinen koodiyksikkö ja kumpi on toinen. Tämä tekee UTF-16: sta itsesynkronoituvan.

nyt mitä meillä on 10 bittiä koodiyksikköä kohti pelattavana, mikä on se alue, jonka sisällä voimme pelata? Kuinka monta merkkiä voidaan lopulta koodata kahteen UTF-16-koodausyksikköön?

ei hätää, puhutaan vain yhteen koodiyksikköön koodatuista merkeistä.

Jos tarkastelet yllä olevia koodiyksikkömalleja, meillä on vaihteluväli 1101 1000 0000 0000₂-1101 1111 1111 1111₂. Sitä vastaa d800₁ to Ja dfff₁₆.

💡 ensimmäisen koodiyksikön vaihteluväli on d800₁-6FFF₁₆ ja toisen koodiyksikön vaihteluväli dc00₁-dfff₁₆. Voimme saada nämä arvot kääntämällä kaikki koodi pistettä bittiä: päälle ja pois päältä.

koska UTF-16: n on oltava itsesynkronoiva, Koodipisteet d800₁: n ja DFFF₁: n välillä eivät saa edustaa UTF-16: n merkkiä. Koska kaikki UTF-koodaukset noudattavat samaa UTF-merkistöä, näitä koodipisteitä rajoittaa UTF, eikä niitä anneta eikä osoiteta millekään merkistölle⁰.

Koodipisteet d800₁: n ja DFFF₁: n välillä eivät edusta mitään merkkejä, joten niitä kutsutaan sijakoodipisteiksi tai yhdessä niitä kutsutaan myös sijakoodipareiksi⁰.

ensimmäistä sijakoodipistettä (ensimmäisestä koodiyksiköstä) kutsutaan myös nimellä high surrogate ja toista koodipistettä (toisesta koodiyksiköstä) kutsutaan myös nimellä low surrogate. Yhteensä 2048 koodipistettä, 1024 per sijainen.

💁 ♂ korvaavat Koodipisteet uhrasivat henkensä, jotta voisimme koodata lisää merkkejä kahdella koodiyksiköllä. Mieti sitä!

joten suuri kysymys, voimmeko koodata merkin yhdellä koodiyksiköllä UTF-16? Vastaus on kyllä. UTF-16 on 16-bittinen muuttuvapituinen koodausjärjestelmä. Tarkoittaako tämä, että voimme koodata 21⁶ merkkiä yhdellä koodiyksiköllä?

vastaus on ei. Teoriassa voisimme koodata 21⁶ merkkiä koodipisteellä 0000₁₆ (0₁₀) ffff₁₆ (65535₀₀), mutta Koodipisteet d800₁ ja DFFF₁₆ eivät edusta mitään merkkejä, koska ne ovat varattuja.

näin ollen on turvallista koodata merkkejä 0000₁-D7FF₁₆ ja e000₁ F-FFFF₁₆, joista jää jäljelle 63 488 (65536-2048) merkkiä. Tämä on vain merkkejä, jotka voidaan koodata vain yksi koodi yksikkö UTF-16.

koska meillä on yhteensä 20 bittiä pelattavana, kun kyse on merkeistä, kuin voidaan koodata 2 koodiyksikköä UTF-16: sta, voimme koodata 22⁰ enemmän merkkejä, mikä on 1 048 576 merkkiä.

joten yhteensä, voimme koodata 1,048,576 + 63,488 joka on 1,112,064 merkkiä (yli 1Million merkkiä). Tämä on UTF-merkistön raja. Koska UTF-16 voi koodata näitä monia merkkejä, muut UTF-koodaukset eivät voi edustaa merkkejä näiden lisäksi.

UTF charset Code Points

koska tiedämme, että koodipiste on merkille annettu desimaaliarvo, emme (Unicode) saa antaa virheellistä koodipistettä varsinaiselle merkille. Toistaiseksi virheelliset Koodipisteet ovat korvaavia koodipisteitä.

vain yhdellä UTF-16-koodiyksiköllä voidaan koodata 63 488 merkkiä, jotka vaihtelevat 0000₁₁-D7FF₁₆ ja E000₁ F-FFFF₁₆. Viimeinen koodipiste on 65 535. Näitä kutsutaan BMP-merkeiksi (selitetty myöhemmin).

kahdella UTF-16: n koodiyksiköllä voidaan koodata 1 048 576 merkkiä. Koska emme voi taas aloittaa 0-arvosta (koodipiste), koska nämä tulevat BMP-merkkien jälkeen, meidän on korvattava ne 65,536: lla. Näitä merkkejä kutsutaan täydentäviksi merkeiksi (selitetty myöhemmin).

näin ollen ensimmäisen lisämerkin koodipistearvo on 65536₀₀, joka vastaa 10000₁₆. Koska voimme koodata 1 048 576 merkkiä kahdella koodiyksiköllä UTF-16, viimeinen koodipiste on 1114111₀, joka vastaa 10ffff₁₆.

joten eritellään asiat yksinkertaiseen taulukkomuotoon.

+-----------+---------------------+--------------------+
| 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 |
+-----------+---------------------+--------------------+

tällä tiedolla katsotaan, miten voimme koodata joitakin UTF-16: n merkkejä. Valitaan yksinkertainen ASCII-merkki a (koodipiste: 41₁₆), hindin (Intian) kielen merkki आ (lausutaan Aa, koodipiste: 906₁₆) ja hymiö 😊 (kutsutaan nimellä Happy face, koodipiste: 1f60a₁₆).

kuten yllä olevasta taulukosta näkyy, sekä A että आ voidaan koodata vain yhteen koodiyksikköön UTF-16, koska niiden arvot ovat pienempiä kuin FFFF₁₆.

kun joudumme koodaamaan merkin vain yhteen koodiyksikköön, joudumme vain muuntamaan merkin koodipisteen 16-bittiseen binäärilukuun. Merkistölle a, 00000000 01000001 ICS on UTF-16 edustus.

vastaavasti merkille आ on vain muunnettava sen koodipiste 906₁ 16-bittiseksi binääriluvuksi, joka on 00001001 00000110₂.

tavallisesti merkistön koodiyksiköt esitetään heksadesimaalilukuina. Näin ollen merkin A UTF-16 edustus on 0041₁₆ ja vastaavasti merkin UTF-16 edustus आ on 0906₁₆.

merkin 😊 kohdalla asiat ovat hieman toisin. Sen koodipiste on 1f60a₁. Jos katsomme edellä mainittua UTF-16-taulukkoa, se on koodattava UTF-16: n 2-koodiyksiköksi. Miten aloitamme?

ensin on vähennettävä koodipisteestä 10000₁₆. Syynä tähän on se, että jokainen UTF-16: n 2 koodiyksikköön koodattu merkki on tullut niiden BMP-merkkien jälkeen, joiden viimeinen koodipiste on FFFF₁₆.

näin ollen saada todellinen arvo bittien käytetään koodaus (joka on 20 in 2 koodi yksikköä), meidän täytyy vähentää 10000₁ koodipisteestä ja käyttää lopullinen numero tuottaa nämä 20 bittiä.

💡 jotta ymmärtäisit paremmin, ensimmäisen UTF-16: n 2 koodiyksiköllä esitetyn merkin kaikki 20 bittiä asetetaan arvoon 0. Tämän merkin koodipisteen koodaamiseen käytettyjen bittien arvo on siis 0. Mutta silti sen koodipiste on Unicode-merkistön mukaan 10000₁₆. Tämä johtuu siitä, että näiden 20 bitin tuottama arvo lisätään 10000₁₁: iin lopullisen koodipisteen aikaansaamiseksi.

kuten aiemmin on nähty, nämä 2 koodiyksikköä näyttävät alla.

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

meidän tarvitsee vain täyttää nämä 20 bittiä (x) merkkikoodipisteestä saadulla arvolla. Merkin 😊koodipiste on 1f60a₁₆. Mutta ensin meidän täytyy vähentää 10000₁ siitä. Saamme F60A₁₆.

nyt on muunnettava F60A₁₆ 20-bittiseksi binääriluvuksi ja täytettävä 20 bittiä edellä mainitussa koodiyksikkömallissa. Binaarissa F60A₁₆ on 0000111101 1000001010₂. Nyt voimme täyttää nämä 20 paikkaa.

alla on lopulliset koodiyksiköt.

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

nopea tapa tarkistaa, ovatko nämä koodiyksiköt kelvollisia ja itse asiassa jos nämä sijaisparit voivat edustaa koodattua merkkiä, avaa selaimen DevTool ja syötä console.log('\uD83D\uDE0A'); konsoliin.

(Kromi kehittäjätyökalut)

voit myös käyttää tätä verkkotyökalua UTF-16-koodipisteiden tuottamiseen.

Unicode-merkistöt

taso on 21⁶ tai 65,536 koodipisteen yhtäjaksoinen ryhmä. Koska UTF-16: ssa on rajoitettu koodipisteitä enintään 10FFFF₁₁, meillä on Unicode-standardissa yhteensä 17 merkin tasoja alkaen 0: sta 16: een.

koska 21⁶ merkkiä voidaan määritellä UTF-16: n yksittäisellä koodiyksiköllä (mukaan lukien sijakoodipisteet), se muodostaa ensimmäisen (0.) tason. Tämä taso sisältää lähes kaikki merkit peruskielissä ympäri maailmaa. Tämän vuoksi tätä tasoa kutsutaan monikieliseksi perustasoksi tai BMP: ksi.

seuraavaksi on Koodipisteet määritelty kahdella UTF-16: n koodiyksiköllä. Nämä sisältävät 22⁰ merkkiä, koska meillä on 20 bittiä koodata koodin pisteen arvo. Nämä jaetaan 16 tasoon (2⁴ X 21⁶). Näitä kutsutaan täydentäviksi lentokoneiksi.

💡 lisätietoja näistä tasoista löytyy tästä Wikipedian dokumentista.

Vertailu UCS-2: een

UCS-2: een on 16-bittinen kiinteälevyinen koodaus. Tämä tarkoittaa, että vain yhtä 16-bittistä koodiyksikköä käytetään kuvaamaan koodipistettä. Teoriassa UCS-2 voi edustaa 21⁶ eri merkkiä, mutta on olemassa kierre.

💡 btw, käytämme termikoodiyksikköä tässä kiinteälevyisessä koodauksessa ymmärtääksemme UTF-16: n välisen suhteen. Todellisuudessa, ei ole olemassa sellaista asiaa kuin koodi yksikkö missään kiinteä koodaus.

koska UCS noudattaa Unicode-merkistöä, UCS-2: n merkkien koodaus on sama kuin UTF-16: n merkkien, jotka on esitetty vain yhdessä koodiyksikössä.

💡 koska UCS noudattaa Unicode-merkistöä, se ei voi koodata kelvollista merkkiä korvikkeille varatuilla koodipisteillä.

joten pähkinänkuoressa UCS-2 sisältää monikielisen perustason merkit. Tämä on syy, jotkut vanhemmat asiakirjat, ja ohjelmisto käyttää UCS-2 koodaus. UCS-2-koodaus on kuitenkin vanhentunut ja UTF-16 on suosittu.

Endianess ja BOM

kuten aiemmin keskustelimme, UTF-koodatut dokumentit matalalla tasolla sisältävät koodiyksiköiden sarjan. UTF-8: ssa koodiyksikkö on 8 bittiä pitkä, kun taas UTF-16: ssa se on 16 bittiä pitkä. Nämä koodiyksiköt muodostavat merkit.

UTF-8-tai UTF-16-dekooderi lukee koodiyksiköt peräkkäin, yksi koodiyksikkö kerrallaan, jotta merkit saadaan luotua.

jokainen koodiyksikkö edustaa numeerista arvoa, jota UTF-8 tai UTF-16-dekooderi voi tarkastella ja päättää, riittääkö merkin edustaminen vai seuraako se myös muita koodiyksiköitä, jotka on otettava huomioon.

UTF-8: n kohdalla asiat ovat yksinkertaisia. Koska jokainen koodiyksikkö on 8 bittiä pitkä, kyseisen 8-bittisen binääriluvun muuntaminen numeeriseksi arvoksi on nopeaa ja helppoa. UTF-16: n kohdalla näin ei kuitenkaan ole.

UTF-16-koodiyksikkö on 16-bittinen (2 tavua) binääriluku, joka edustaa koodin pistearvoa. Numeerisen arvon luominen useasta tavusta on yleensä hankalaa ja eri järjestelmät käyttäytyvät eri tavoin.

tämä käyttäytyminen riippuu systeemin endianssista. Aiemmasta keskustelustamme endianessista, on kaksi tapaa, joilla voimme kirjoittaa UTF-16-koodin yksikköarvon. Joko iso-endian-muodossa tai pikku-endian-muodossa.

Big-endian-muodossa MSB tallennetaan ensimmäisenä ja LSB viimeisenä. Toistaiseksi kirjoitamme UTF-16-koodin yksikköarvoa Iso-endian-muodossa. Jos haluat kirjoittaa UTF-16-koodin yksikköarvon Little-endianilla, meidän on vaihdettava tavuja.

puhutaan hahmosta आ. Aiemmasta esimerkistä se voidaan esittää vain yhdellä UTF-16: n koodiyksiköllä ja sen koodaus heksadesimaaliesityksessä näyttää 0906₁₆.

0906₁₆ on 16-bittinen luku, jossa 09 on MSB ja 06 on LSB. Siksi Big-endian arkkitehtuurissa se tallennetaan nimellä 09 06. Vähän-endiläisessä arkkitehtuurissa se kuitenkin tallennetaan nimellä 06 09.

näin ollen tulee velvollisuudeksemme koodata merkkejä ottamalla huomioon järjestelmän loppuosa, jotta järjestelmä voi lukea UTF-16-dokumentin oikein.

mutta miten voimme etukäteen tietää, onko käyttäjän kone yhteensopiva koodatun dokumentin kanssa vai ei? Ja koska järjestelmän loppumattomuus voi vaikuttaa siihen, miten dokumentti puretaan, niin miten me jaamme sen julkisesti?

tässä kohtaa kuvaan astuu BOM. Tavujärjestysmerkki (Bom) on tavujärjestys, joka lisätään tekstitiedoston tai tekstidatan alkuun.

Unicode suosittelee merkkiä koodipisteellä FEFF₁ toimimaan BOM: nä UTF-16-ja UTF-32-koodauksille. Tämän merkin pitäisi olla ennen asiakirjan ensimmäistä merkkiä. Kuitenkin, tämä merkki ei oteta huomioon dekooderi ulostulossa.

tämä merkki (U+FEFF) on nollalevyinen murtamaton avaruus (ZWNBSP)-merkki ja se on näkymätön. Näin ollen vaikka dekooderi ei tunnista BOM, se ei tuota mitään näkyvää ulostuloa.

tämä merkki esitetään UTF-16: n yksittäisessä koodiyksikössä ja heksadesimaalisessa esityksessä se näyttää Fe: ltä (MSB) ja FF: ltä (LSB).

näin ollen kun merkit on koodattu Iso-endian muodossa, meidän täytyy lisätä FEFF kuin BOM alussa tiedoston ja kun merkit on koodattu pikku-endian muodossa, meidän täytyy lisätä FFFE (Käänteinen) kuin BOM alussa tiedoston.

Unicode suosittelee BOM: n lisäämistä UTF-16-koodattuun dokumenttiin. Jos BOM kuitenkin puuttuu, oletetaan Big-endian-muoto.

IANA suosii UTF-16: ta tunnisteena merkitäkseen UTF-16: ta koodattua asiakirjaa. UTF-16BE: tä käytetään kuitenkin dokumentissa, joka on koodattu Big-endian-muotoon ja UTF-16LE: tä käytetään Little-endian-muotoon.

kun käytetään UTF-16BE-tai UTF-16LE-nimeä, BOM: ää ei suositella valmiiksi tiedostoksi. Tässäkin tapauksessa, jos BOM lisätään, se katsotaan ZWNBSP merkki ja sitä ei ohiteta.

💡 UTF-16, UTF-16BE ja UTF-16LE nimet ovat asiattomia.

plussat ja miinukset

UTF-16 on tehokas, koska siinä on vain 2 koodiyksikköä ja koska useimmat käytetyt merkit kuuluvat BMP-joukkoon, ne voidaan esittää vain yhtenä koodiyksikkönä. Kuitenkin, se tulee paljon kysymyksiä.

UTF-16: n suurin haitta on se, että se ei ole ASCII-yhteensopiva. Koska ASCII-merkit on koodattu yhdellä koodiyksiköllä (16-bittinen numero), niitä ei voi purkaa kunnolla ASCII-dekooderilla.

UTF-16 kuluttaa tarpeetonta tilaa ASCII-merkeille. Verrattuna vain ASCII-merkkejä sisältävään UTF-8-koodattuun dokumenttiin saman UTF-16-koodatun dokumentin koko on kaksi kertaa suurempi.

UTF-16: een vaikuttaa myös järjestelmän loppumattomuus. Jos BOM puuttuu ja asianmukaista koodaustunnusta ei käytetä (kuten UTF-16LE), UTF-16-koodattua asiakirjaa ei välttämättä saada purettua oikein.

UTF-16-koodauksen luonteen vuoksi se on ottanut käyttöön korvaavia koodipisteitä, jotka eivät voi edustaa kelvollisia merkkejä. Lisäksi se on rajoittanut Unicode-merkistön arvoon 10FFFF₁ (viimeinen koodipiste).

näistä tosiasioista huolimatta osa ohjelmointikielistä kuten JavaScript, Java jne. ja järjestelmät, kuten Windows, suosivat UTF-16-koodausta.

Vastaa

Sähköpostiosoitettasi ei julkaista.