Ja esat izstrÄdÄtÄjs un jÅ«s saskaraties ar uzdevumu izvÄlÄties kodÄjumu, Unicode gandrÄ«z vienmÄr bÅ«s pareizais risinÄjums. KonkrÄtÄ attÄlojuma metode ir atkarÄ«ga no konteksta, taÄu visbiežÄk arÄ« Å”eit ir universÄla atbilde - UTF-8. LabÄ lieta ir tÄ, ka tas ļauj izmantot visas Unikoda rakstzÄ«mes bez tÄriÅiem pÄrÄk daudz vairumÄ gadÄ«jumu daudz baitu. Tiesa, valodÄm, kurÄs tiek lietots vairÄk nekÄ tikai latÄ«Åu alfabÄts, āne pÄrÄk daudzā ir vismaz divi baiti katrai rakstzÄ«mei. Vai mÄs varam darÄ«t labÄk, neatgriežoties pie aizvÄsturiskiem kodumiem, kas ierobežo tikai 256 pieejamÄs rakstzÄ«mes?
ZemÄk es ierosinu iepazÄ«ties ar manu mÄÄ£inÄjumu atbildÄt uz Å”o jautÄjumu un ieviest salÄ«dzinoÅ”i vienkÄrÅ”u algoritmu, kas ļauj saglabÄt lÄ«nijas lielÄkajÄ daÄ¼Ä pasaules valodu, nepievienojot UTF-8 dublÄÅ”anos.
Atruna. Es nekavÄjoties izdarÄ«Å”u dažas svarÄ«gas atrunas: aprakstÄ«tais risinÄjums netiek piedÄvÄts kÄ universÄls UTF-8 aizstÄjÄjs, tas ir piemÄrots tikai Å”aurÄ gadÄ«jumu sarakstÄ (vairÄk par tiem tÄlÄk), un nekÄdÄ gadÄ«jumÄ to nedrÄ«kst izmantot, lai mijiedarbotos ar treÅ”o puÅ”u API (kuri par to pat nezina). VisbiežÄk liela apjoma teksta datu kompaktai glabÄÅ”anai ir piemÄroti vispÄrÄjas nozÄ«mes saspieÅ”anas algoritmi (piemÄram, deflÄcija). TurklÄt jau sava risinÄjuma tapÅ”anas procesÄ es atradu jau esoÅ”u standartu paÅ”Ä Unicode, kas atrisina to paÅ”u problÄmu - tas ir nedaudz sarežģītÄks (un bieži vien sliktÄks), bet tomÄr tas ir pieÅemts standarts, nevis vienkÄrÅ”i ievietots. kopÄ uz ceļa. Es tev arÄ« pastÄstÄ«Å”u par viÅu.
Par Unicode un UTF-8
SÄkumÄ daži vÄrdi par to, kas tas ir Unikode Šø UTF-8.
KÄ zinÄms, 8 bitu kodÄjumi agrÄk bija populÄri. Ar tiem viss bija vienkÄrÅ”i: 256 rakstzÄ«mes var numurÄt ar cipariem no 0 lÄ«dz 255, un skaitļus no 0 lÄ«dz 255 acÄ«mredzot var attÄlot kÄ vienu baitu. Ja mÄs atgriežamies paÅ”Ä sÄkumÄ, tad ASCII kodÄjums ir pilnÄ«bÄ ierobežots lÄ«dz 7 bitiem, tÄpÄc nozÄ«mÄ«gÄkais bits tÄ baitu attÄlojumÄ ir nulle, un lielÄkÄ daļa 8 bitu kodÄjumu ir ar to saderÄ«gi (tie atŔķiras tikai ar āaugÅ”Äjoā daļa, kur nozÄ«mÄ«gÄkais bits ir viens ).
Ar ko Unicode atŔķiras no Å”iem kodÄjumiem un kÄpÄc ar to ir saistÄ«ti tik daudzi specifiski attÄlojumi - UTF-8, UTF-16 (BE un LE), UTF-32? SakÄrtosim to secÄ«bÄ.
Unikoda pamatstandarts apraksta tikai atbilstÄ«bu starp rakstzÄ«mÄm (un dažos gadÄ«jumos atseviŔķiem rakstzÄ«mju komponentiem) un to numuriem. Un Å”ajÄ standartÄ ir daudz iespÄjamo skaitļu - no 0x00
līdz 0x10FFFF
(1 114 112 gab.). Ja mÄs gribÄtu ielikt mainÄ«gajÄ skaitli Å”ÄdÄ diapazonÄ, mums nepietiktu ne ar 1, ne 2 baitiem. Un tÄ kÄ mÅ«su procesori nav Ä«paÅ”i paredzÄti darbam ar trÄ«s baitu cipariem, mÄs bÅ«tu spiesti izmantot pat 4 baitus uz vienu rakstzÄ«mi! Tas ir UTF-32, taÄu tieÅ”i Ŕīs āizŔķÄrdÄ«basā dÄļ Å”is formÄts nav populÄrs.
Par laimi, rakstzÄ«mju secÄ«ba Unicode nav nejauÅ”a. ViÅu viss komplekts ir sadalÄ«ts 17 "lidmaŔīnas", no kuriem katrs satur 65536 (0x10000
) Ā«koda punkti" āKoda punktaā jÄdziens Å”eit ir vienkÄrÅ”s rakstzÄ«mju numurs, ko tam pieŔķīris Unicode. Bet, kÄ minÄts iepriekÅ”, Unicode ir numurÄtas ne tikai atseviŔķas rakstzÄ«mes, bet arÄ« to sastÄvdaļas un servisa zÄ«mes (un dažreiz arÄ« nekas neatbilst ciparam - varbÅ«t pagaidÄm, bet mums tas nav tik svarÄ«gi), tÄpÄc pareizÄk vienmÄr runÄt konkrÄti par paÅ”u skaitļu skaitu, nevis simboliem. TomÄr turpmÄk tekstÄ Ä«suma labad bieži izmantoÅ”u vÄrdu āsimbolsā, kas nozÄ«mÄ terminu ākoda punktsā.
Unikoda lidmaŔīnas. KÄ redzat, lielÄkÄ daļa (4. lÄ«dz 13. lidmaŔīnas) joprojÄm ir neizmantota.
IevÄrojamÄkais ir tas, ka visa galvenÄ "celuloze" atrodas nulles plaknÄ, to sauc par "Pamata daudzvalodu plakne". Ja rindÄ ir teksts kÄdÄ no mÅ«sdienu valodÄm (ieskaitot Ä·Ä«nieÅ”u), jÅ«s netiksiet tÄlÄk par Å”o plakni. Bet jÅ«s nevarat arÄ« nogriezt pÄrÄjo Unikoda daļu - piemÄram, emocijzÄ«mes galvenokÄrt atrodas valodas beigÄs nÄkamÄ lidmaŔīna"Papildu daudzvalodu plakne"(tas stiepjas no 0x10000
līdz 0x1FFFF
). TÄtad UTF-16 dara to: visas rakstzÄ«mes, kas ietilpst Pamata daudzvalodu plakne, ir kodÄti ākÄ irā ar atbilstoÅ”u divu baitu numuru. TomÄr daži skaitļi Å”ajÄ diapazonÄ vispÄr nenorÄda konkrÄtas rakstzÄ«mes, bet norÄda, ka pÄc Ŕī baitu pÄra mums ir jÄÅem vÄrÄ vÄl viens - apvienojot Å”o Äetru baitu vÄrtÄ«bas kopÄ, mÄs iegÅ«stam skaitli, kas aptver viss derÄ«gais Unikoda diapazons. Å o ideju sauc par "surogÄtpÄriem" ā jÅ«s, iespÄjams, esat par tiem dzirdÄjuÅ”i.
TÄtad UTF-16 katram "koda punktam" ir nepiecieÅ”ami divi vai (ļoti retos gadÄ«jumos) Äetri baiti. Tas ir labÄk, nekÄ visu laiku izmantot Äetrus baitus, taÄu latÄ«Åu valoda (un citas ASCII rakstzÄ«mes), ja tÄ tiek kodÄta, pusi no vietas iztÄrÄ uz nullÄm. UTF-8 ir paredzÄts, lai to labotu: ASCII tajÄ, tÄpat kÄ iepriekÅ”, aizÅem tikai vienu baitu; kodi no 0x80
līdz 0x7FF
- divi baiti; no 0x800
līdz 0xFFFF
- trīs, un no 0x10000
līdz 0x10FFFF
- Äetras. No vienas puses, latÄ«Åu alfabÄts ir kļuvis labs: ir atgriezusies saderÄ«ba ar ASCII, un sadalÄ«jums ir vienmÄrÄ«gÄk āizkliedÄtsā no 1 lÄ«dz 4 baitiem. DiemžÄl citiem alfabÄtiem, izÅemot latÄ«Åu alfabÄtu, nav nekÄda labuma salÄ«dzinÄjumÄ ar UTF-16, un daudziem tagad ir nepiecieÅ”ami trÄ«s baiti, nevis divi ā divu baitu ierakstu aptvertais diapazons ir samazinÄjies par 32 reizÄm. 0xFFFF
līdz 0x7FF
, un tajÄ nav iekļauta ne Ä·Ä«nieÅ”u, ne, piemÄram, gruzÄ«nu valoda. Kirilica un pieci citi alfabÄti - urrÄ - laimÄ«gs, 2 baiti katrai rakstzÄ«mei.
KÄpÄc tas notiek? ApskatÄ«sim, kÄ UTF-8 apzÄ«mÄ rakstzÄ«mju kodus:
TieÅ”i skaitļu attÄloÅ”anai Å”eit tiek izmantoti biti, kas apzÄ«mÄti ar simbolu x
. Var redzÄt, ka divu baitu ierakstÄ ir tikai 11 Å”Ädi biti (no 16). Å eit vadoÅ”ajiem bitiem ir tikai palÄ«gfunkcija. Äetru baitu ieraksta gadÄ«jumÄ koda punkta numuram tiek atvÄlÄts 21 no 32 bitiem - Ŕķiet, ka pietiktu ar trim baitiem (kas kopÄ dod 24 bitus), taÄu servisa marÄ·ieri apÄd pÄrÄk daudz.
Vai tas ir slikti? Ne Ä«sti. No vienas puses, ja mums ļoti rÅ«p telpa, mums ir saspieÅ”anas algoritmi, kas var viegli novÄrst visu papildu entropiju un dublÄÅ”anos. No otras puses, Unicode mÄrÄ·is bija nodroÅ”inÄt pÄc iespÄjas universÄlÄko kodÄÅ”anu. PiemÄram, mÄs varam uzticÄt UTF-8 kodÄtu rindiÅu kodam, kas iepriekÅ” darbojÄs tikai ar ASCII, un nebaidÄ«ties, ka tÄ redzÄs rakstzÄ«mi no ASCII diapazona, kuras patiesÄ«bÄ nav (galu galÄ UTF-8 baiti, kas sÄkas ar nulles bitu ā tieÅ”i tas ir ASCII). Un, ja mÄs pÄkÅ”Åi vÄlamies no lielas virknes nogriezt mazu asti, neatÅ”ifrÄjot to no paÅ”a sÄkuma (vai atjaunot daļu informÄcijas pÄc bojÄtas sadaļas), mums ir viegli atrast nobÄ«di, kur sÄkas rakstzÄ«me (pietiek lai izlaistu baitus, kuriem ir bits prefikss 10
).
KÄpÄc tad izgudrot kaut ko jaunu?
TajÄ paÅ”Ä laikÄ dažkÄrt ir situÄcijas, kad kompresijas algoritmi, piemÄram, deflÄcija, ir slikti piemÄrojami, bet vÄlaties panÄkt kompaktu virkÅu glabÄÅ”anu. PersonÄ«gi es saskÄros ar Å”o problÄmu, domÄjot par bÅ«vniecÄ«bu
AtseviŔķi es vÄlÄtos atzÄ«mÄt vÄl vienu nepatÄ«kamu niansi, kas rodas, izmantojot UTF-8 Å”ÄdÄ datu struktÅ«rÄ. AugÅ”ÄjÄ attÄlÄ redzams, ka, rakstot rakstzÄ«mi kÄ divus baitus, ar tÄs numuru saistÄ«tie biti nenÄk pÄc kÄrtas, bet tiek atdalÄ«ti ar bitu pÄri. 10
vidū: 110xxxxx 10xxxxxx
. SakarÄ ar to, kad otrÄ baita apakÅ”Äjie 6 biti pÄrplÅ«st rakstzÄ«mju kodÄ (t.i., notiek pÄreja 10111111
ā 10000000
), mainÄs arÄ« pirmais baits. IzrÄdÄs, ka burts āpā tiek apzÄ«mÄts ar baitiem 0xD0 0xBF
, un nÄkamais ārā jau ir 0xD1 0x80
. Prefiksu kokÄ tas noved pie vecÄkmezgla sadalÄ«Å”anas divÄs daļÄs ā vienu prefiksam 0xD0
, un vÄl viens par 0xD1
(lai gan visu kirilicas alfabÄtu varÄja kodÄt tikai ar otro baitu).
Ko es dabūju
Saskaroties ar Å”o problÄmu, es nolÄmu praktizÄt spÄles ar bitiem un tajÄ paÅ”Ä laikÄ nedaudz labÄk iepazÄ«ties ar Unicode struktÅ«ru kopumÄ. RezultÄtÄ tika izveidots UTF-C kodÄÅ”anas formÄts (āCā ā kompakts), kas vienam koda punktam tÄrÄ ne vairÄk kÄ 3 baitus un ļoti bieži ļauj tÄrÄt tikai viens papildu baits visai kodÄtajai lÄ«nijai. Tas noved pie tÄ, ka daudzos alfabÄtÄ, kas nav ASCII alfabÄts, Å”Äds kodÄjums izrÄdÄs 30ā60% kompaktÄks nekÄ UTF-8.
Esmu parÄdÄ«jis kodÄÅ”anas un dekodÄÅ”anas algoritmu ievieÅ”anas piemÄrus formÄ
Testa rezultÄti un salÄ«dzinÄjums ar UTF-8
Es arī darīju
Lieku bitu likvidÄÅ”ana
Par pamatu, protams, ÅÄmu UTF-8. PirmÄ un acÄ«mredzamÄkÄ lieta, ko tajÄ var mainÄ«t, ir samazinÄt pakalpojumu bitu skaitu katrÄ baitÄ. PiemÄram, pirmais baits UTF-8 vienmÄr sÄkas ar vienu vai otru 0
, vai ar 11
- prefikss 10
Tas ir tikai nÄkamajos baitos. AizstÄsim prefiksu 11
par 1
, un nÄkamajiem baitiem mÄs pilnÄ«bÄ noÅemsim prefiksus. Kas notiks?
0xxxxxxx
ā 1 baits
10xxxxxx xxxxxxxx
- 2 baiti
110xxxxx xxxxxxxx xxxxxxxx
- 3 baiti
Pagaidiet, kur ir Äetru baitu ieraksts? Bet tas vairs nav vajadzÄ«gs - rakstot trÄ«s baitos, mums tagad ir pieejams 21 bits un ar to pietiek visiem cipariem lÄ«dz 0x10FFFF
.
Ko mÄs Å”eit esam upurÄjuÅ”i? VissvarÄ«gÄkais ir rakstzÄ«mju robežu noteikÅ”ana no patvaļīgas atraÅ”anÄs vietas buferÄ«. MÄs nevaram norÄdÄ«t uz patvaļīgu baitu un no tÄ atrast nÄkamÄs rakstzÄ«mes sÄkumu. Tas ir mÅ«su formÄta ierobežojums, taÄu praksÄ tas ir reti nepiecieÅ”ams. MÄs parasti spÄjam izskriet buferi jau no paÅ”a sÄkuma (Ä«paÅ”i, ja runa ir par Ä«sÄm lÄ«nijÄm).
SituÄcija ar valodu pÄrklÄjumu ar 2 baitiem arÄ« ir kļuvusi labÄka: tagad divu baitu formÄts nodroÅ”ina 14 bitu diapazonu, un tie ir kodi lÄ«dz 0x3FFF
. ĶīnieÅ”iem nav paveicies (viÅu rakstzÄ«mes lielÄkoties ir no 0x4E00
līdz 0x9FFF
), taÄu gruzÄ«niem un daudzÄm citÄm tautÄm ir daudz jautrÄ«bas ā arÄ« viÅu valodas iekļaujas 2 baitos uz vienu rakstzÄ«mi.
Ievadiet kodÄtÄja stÄvokli
Tagad padomÄsim par paÅ”u lÄ«niju Ä«paŔībÄm. VÄrdnÄ«cÄ visbiežÄk ir vÄrdi, kas rakstÄ«ti ar viena un tÄ paÅ”a alfabÄta rakstzÄ«mÄm, un tas attiecas arÄ« uz daudziem citiem tekstiem. BÅ«tu labi vienreiz norÄdÄ«t Å”o alfabÄtu un pÄc tam norÄdÄ«t tikai tajÄ esoÅ”Ä burta numuru. RedzÄsim, vai rakstzÄ«mju izkÄrtojums Unikoda tabulÄ mums palÄ«dzÄs.
KÄ minÄts iepriekÅ”, Unicode ir sadalÄ«ts lidmaŔīna 65536 kodi katrÄ. Bet tas nav Ä«paÅ”i noderÄ«gs sadalÄ«jums (kÄ jau teikts, visbiežÄk mÄs atrodamies nulles plaknÄ). InteresantÄks ir dalÄ«jums pÄc bloki. Å iem diapazoniem vairs nav fiksÄta garuma, un tie ir nozÄ«mÄ«gÄki ā parasti katrs apvieno rakstzÄ«mes no viena un tÄ paÅ”a alfabÄta.
Bloks, kurÄ ir bengÄļu alfabÄta rakstzÄ«mes. DiemžÄl vÄsturisku iemeslu dÄļ Å”is ir ne pÄrÄk blÄ«va iepakojuma piemÄrs ā 96 rakstzÄ«mes ir haotiski izkaisÄ«tas pa 128 bloka koda punktiem.
Bloku pirmsÄkumi un to izmÄri vienmÄr ir 16 reizes ā tas tiek darÄ«ts vienkÄrÅ”i ÄrtÄ«bas labad. TurklÄt daudzi bloki sÄkas un beidzas ar vÄrtÄ«bÄm, kas reizinÄs ar 128 vai pat 256 - piemÄram, pamata kirilicas alfabÄts aizÅem 256 baitus no 0x0400
līdz 0x04FF
. Tas ir diezgan Ärti: ja vienreiz saglabÄjam prefiksu 0x04
, tad vienÄ baitÄ var ierakstÄ«t jebkuru kirilicas rakstzÄ«mi. Tiesa, tÄdÄ veidÄ mÄs zaudÄsim iespÄju atgriezties pie ASCII (un vispÄr pie jebkÄdÄm citÄm rakstzÄ«mÄm). TÄpÄc mÄs rÄ«kojamies Å”Ädi:
- Divi baiti
10yyyyyy yxxxxxxx
ne tikai apzÄ«mÄ simbolu ar skaitliyyyyyy yxxxxxxx
, bet arÄ« mainÄ«t paÅ”reizÄjais alfabÄts paryyyyyy y0000000
(t.i., mÄs atceramies visus bitus, izÅemot vismazÄk nozÄ«mÄ«gus 7 bits); - Viens baits
0xxxxxxx
tas ir paÅ”reizÄjÄ alfabÄta raksturs. Tas vienkÄrÅ”i jÄpievieno nobÄ«dei, ko atcerÄjÄmies 1. darbÄ«bÄ. Lai gan mÄs nemainÄ«jÄm alfabÄtu, nobÄ«de ir nulle, tÄpÄc saglabÄjÄm saderÄ«bu ar ASCII.
TÄpat kodiem, kuriem nepiecieÅ”ami 3 baiti:
- Trīs baiti
110yyyyy yxxxxxxx xxxxxxxx
norÄdiet simbolu ar skaitliyyyyyy yxxxxxxx xxxxxxxx
, mainÄ«t paÅ”reizÄjais alfabÄts paryyyyyy y0000000 00000000
(atcerÄjÄs visu, izÅemot jaunÄkos 15 bits) un atzÄ«mÄjiet izvÄles rÅ«tiÅu, kurÄ paÅ”laik atrodamies garÅ” režīms (mainot alfabÄtu atpakaļ uz divbaitu, mÄs atiestatÄ«sim Å”o karogu); - Divi baiti
0xxxxxxx xxxxxxxx
garajÄ režīmÄ tas ir paÅ”reizÄjÄ alfabÄta raksturs. LÄ«dzÄ«gi mÄs to pievienojam ar nobÄ«di no 1. soļa. VienÄ«gÄ atŔķirÄ«ba ir tÄ, ka tagad mÄs nolasÄm divus baitus (jo mÄs pÄrslÄdzÄmies uz Å”o režīmu).
IzklausÄs labi: tagad, kamÄr mums ir jÄkodÄ rakstzÄ«mes no tÄ paÅ”a 7 bitu unikoda diapazona, sÄkumÄ mÄs iztÄrÄjam 1 papildu baitu un kopÄ vienu baitu katrai rakstzÄ«mei.
Darbojas no vienas no iepriekÅ”ÄjÄm versijÄm. Tas jau tagad bieži pÄrspÄj UTF-8, bet vÄl ir kur uzlabot.
Kas ir sliktÄk? PirmkÄrt, mums ir nosacÄ«jums, proti paÅ”reizÄjÄ alfabÄta nobÄ«de un izvÄles rÅ«tiÅa garais režīms. Tas mÅ«s vÄl vairÄk ierobežo: tagad vienas un tÄs paÅ”as rakstzÄ«mes dažÄdos kontekstos var tikt kodÄtas atŔķirÄ«gi. PiemÄram, apakÅ”virkÅu meklÄÅ”ana bÅ«s jÄveic, Åemot vÄrÄ to, nevis tikai salÄ«dzinot baitus. OtrkÄrt, tiklÄ«dz mÄs mainÄ«jÄm alfabÄtu, tas kļuva slikts ar ASCII rakstzÄ«mju kodÄjumu (un tas ir ne tikai latÄ«Åu alfabÄts, bet arÄ« pamata pieturzÄ«mes, ieskaitot atstarpes) - tÄm atkal ir jÄmaina alfabÄts uz 0, tas ir, atkal papildu baits (un pÄc tam vÄl viens, lai atgrieztos pie galvenÄ jautÄjuma).
Viens alfabÄts ir labs, divi ir labÄki
MÄÄ£inÄsim nedaudz mainÄ«t savus bitu prefiksus, saspiežot vÄl vienu lÄ«dz trim iepriekÅ” aprakstÄ«tajiem:
0xxxxxxx
ā 1 baits parastajÄ režīmÄ, 2 garajÄ režīmÄ
11xxxxxx
ā 1 baits
100xxxxx xxxxxxxx
- 2 baiti
101xxxxx xxxxxxxx xxxxxxxx
- 3 baiti
Tagad divu baitu ierakstÄ ir pieejams par vienu bitu mazÄk ā kods norÄda lÄ«dz 0x1FFF
Un ne 0x3FFF
. TomÄr tas joprojÄm ir ievÄrojami lielÄks nekÄ divbaitu UTF-8 kodos, lielÄkÄ daļa izplatÄ«to valodu joprojÄm iekļaujas, visievÄrojamÄkie zaudÄjumi ir izkrituÅ”i
Kas ir Ŕis jaunais kods? 11xxxxxx
? Å Ä« ir maza āatlicinÄtaā ar 64 rakstzÄ«mÄm, tÄ papildina mÅ«su galveno alfabÄtu, tÄpÄc es to nosaucu par palÄ«gu (papildu) alfabÄts. PÄrslÄdzot paÅ”reizÄjo alfabÄtu, vecÄ alfabÄta daļa kļūst par palÄ«gierÄ«ci. PiemÄram, mÄs pÄrgÄjÄm no ASCII uz kirilicu ā tagad atlicinÄtÄ ir 64 rakstzÄ«mes, kas satur LatÄ«Åu alfabÄts, cipari, atstarpe un komats (visbiežÄkie iestarpinÄjumi tekstos, kas nav ASCII). PÄrslÄdzieties atpakaļ uz ASCII ā un galvenÄ kirilicas alfabÄta daļa kļūs par palÄ«galfabÄtu.
Pateicoties piekļuvei diviem alfabÄtiem, mÄs varam apstrÄdÄt lielu skaitu tekstu ar minimÄlÄm izmaksÄm par alfabÄtu pÄrslÄgÅ”anu (pieturzÄ«mes visbiežÄk novedÄ«s pie atgrieÅ”anÄs pie ASCII, bet pÄc tam mÄs iegÅ«sim daudzas rakstzÄ«mes, kas nav ASCII rakstzÄ«mes no papildu alfabÄta, bez pÄrslÄgÅ”anÄs vÄlreiz).
Bonuss: apakÅ”alfabÄta prefikss 11xxxxxx
un izvÄloties tÄ sÄkotnÄjo nobÄ«di 0xC0
, mÄs iegÅ«stam daļÄju saderÄ«bu ar CP1252. Citiem vÄrdiem sakot, daudzi (bet ne visi) Rietumeiropas teksti, kas kodÄti CP1252, UTF-C izskatÄ«sies vienÄdi.
TomÄr Å”eit rodas grÅ«tÄ«bas: kÄ iegÅ«t palÄ«gu no galvenÄ alfabÄta? JÅ«s varat atstÄt to paÅ”u nobÄ«di, bet - diemžÄl - Å”eit Unicode struktÅ«ra jau spÄlÄ pret mums. Ä»oti bieži alfabÄta galvenÄ daļa neatrodas bloka sÄkumÄ (piemÄram, krievu lielajam āAā ir kods 0x0410
, lai gan kirilicas bloks sÄkas ar 0x0400
). TÄdÄjÄdi, paÅemot krÄtuvÄ pirmÄs 64 rakstzÄ«mes, mÄs varam zaudÄt piekļuvi alfabÄta astes daļai.
Lai novÄrstu Å”o problÄmu, es manuÄli izgÄju cauri dažiem blokiem, kas atbilst dažÄdÄm valodÄm, un norÄdÄ«ju tiem papildu alfabÄta nobÄ«di galvenajÄ. LatÄ«Åu alfabÄts kÄ izÅÄmums parasti tika pÄrkÄrtots kÄ base64.
PÄdÄjie pieskÄrieni
Beidzot padomÄsim, kur vÄl kaut ko varÄtu uzlabot.
Å
emiet vÄrÄ, ka formÄts 101xxxxx xxxxxxxx xxxxxxxx
ļauj kodÄt ciparus lÄ«dz 0x1FFFFF
, un Unicode beidzas agrÄk, plkst 0x10FFFF
. Citiem vÄrdiem sakot, pÄdÄjais koda punkts tiks attÄlots kÄ 10110000 11111111 11111111
. TÄpÄc mÄs varam teikt, ka, ja pirmais baits ir formas 1011xxxx
(kur xxxx
lielÄks par 0), tad tas nozÄ«mÄ kaut ko citu. PiemÄram, tur var pievienot vÄl 15 rakstzÄ«mes, kas pastÄvÄ«gi ir pieejamas kodÄÅ”anai vienÄ baitÄ, bet es nolÄmu to darÄ«t savÄdÄk.
ApskatÄ«sim tos Unikoda blokus, kuriem ir nepiecieÅ”ami trÄ«s baiti. BÅ«tÄ«bÄ, kÄ jau minÄts, tÄs ir Ä·Ä«nieÅ”u rakstzÄ«mes, taÄu ar tÄm ir grÅ«ti kaut ko darÄ«t, to ir 21 tÅ«kstotis. Bet tur lidoja arÄ« hiragana un katakana - un viÅu vairs nav tik daudz, nepilni divi simti. Un, tÄ kÄ mÄs atcerÄjÄmies japÄÅus, ir arÄ« emocijzÄ«mes (patiesÄ«bÄ tÄs ir izkaisÄ«tas daudzÄs vietÄs Unicode, bet galvenie bloki ir diapazonÄ 0x1F300
- 0x1FBFF
). Ja domÄjat par to, ka tagad ir emocijzÄ«mes, kas ir saliktas no vairÄkiem koda punktiem vienlaikus (piemÄram, emocijzÄ«mes āāā
TÄpÄc mÄs atlasÄm dažus atlasÄ«tos diapazonus, kas atbilst emocijzÄ«mÄm, hiraganai un katakanai, pÄrnumurÄjam tos vienÄ nepÄrtrauktÄ sarakstÄ un kodÄjam kÄ divus baitus, nevis trÄ«s:
1011xxxx xxxxxxxx
Lieliski: iepriekÅ” minÄtÄ emocijzÄ«me
MÄÄ£inÄsim novÄrst vÄl vienu problÄmu. KÄ mÄs atceramies, pamata alfabÄts bÅ«tÄ«bÄ ir augsts 6 biti, ko paturam prÄtÄ un pielÄ«mÄjam pie katra nÄkamÄ atkodÄtÄ simbola koda. AttiecÄ«bÄ uz Ä·Ä«nieÅ”u rakstzÄ«mÄm, kas ir blokÄ 0x4E00
- 0x9FFF
, tas ir bits 0 vai 1. Tas nav Ä«paÅ”i Ärti: mums bÅ«s nepÄrtraukti jÄpÄrslÄdz alfabÄts starp Ŕīm divÄm vÄrtÄ«bÄm (t.i., jÄiztÄrÄ trÄ«s baiti). Bet Åemiet vÄrÄ, ka garajÄ režīmÄ no paÅ”a koda mÄs varam atÅemt rakstzÄ«mju skaitu, kuras mÄs kodÄjam, izmantojot Ä«so režīmu (pÄc visiem iepriekÅ” aprakstÄ«tajiem trikiem tas ir 10240) - tad hieroglifu diapazons tiks novirzÄ«ts uz 0x2600
- 0x77FF
, un Å”ajÄ gadÄ«jumÄ visÄ Å”ajÄ diapazonÄ nozÄ«mÄ«gÄkie 6 biti (no 21) bÅ«s vienÄdi ar 0. TÄdÄjÄdi hieroglifu secÄ«bas izmantos divus baitus uz vienu hieroglifu (kas ir optimÄli tik lielam diapazonam), bez izraisot alfabÄta slÄdžus.
AlternatÄ«vi risinÄjumi: SCSU, BOCU-1
Unikoda eksperti, tikko izlasÄ«juÅ”i raksta nosaukumu, visticamÄk, steigs atgÄdinÄt, ka tieÅ”i starp Unicode standartiem ir
AtzÄ«Å”os godÄ«gi: par tÄ esamÄ«bu uzzinÄju tikai pÄc tam, kad biju dziļi iegrimis sava lÄmuma rakstÄ«Å”anÄ. Ja es par to bÅ«tu zinÄjis no paÅ”a sÄkuma, es droÅ”i vien bÅ«tu mÄÄ£inÄjis uzrakstÄ«t ievieÅ”anu, nevis nÄkt klajÄ ar savu pieeju.
Interesanti ir tas, ka SCSU izmanto idejas, kas ir ļoti lÄ«dzÄ«gas tÄm, kuras es izdomÄju pats (jÄdziena āalfabÄtsā vietÄ viÅi izmanto ālogusā, un to ir vairÄk nekÄ man). TajÄ paÅ”Ä laikÄ Å”im formÄtam ir arÄ« trÅ«kumi: tas ir nedaudz tuvÄk kompresijas algoritmiem nekÄ kodÄÅ”anas algoritmiem. Jo Ä«paÅ”i standarts sniedz daudzas attÄloÅ”anas metodes, bet nepasaka, kÄ izvÄlÄties optimÄlo - Å”im nolÅ«kam kodÄtÄjam ir jÄizmanto sava veida heiristika. TÄdÄjÄdi SCSU kodÄtÄjs, kas ražo labu iepakojumu, bÅ«s sarežģītÄks un apgrÅ«tinoÅ”Äks nekÄ mans algoritms.
SalÄ«dzinÄjumam uz JavaScript pÄrnesu salÄ«dzinoÅ”i vienkÄrÅ”u SCSU ievieÅ”anu - koda apjoma ziÅÄ tas izrÄdÄ«jÄs salÄ«dzinÄms ar manu UTF-C, bet dažos gadÄ«jumos rezultÄts bija par desmitiem procentu sliktÄks (dažkÄrt var arÄ« pÄrsniegt, bet ne daudz). PiemÄram, teksti ebreju un grieÄ·u valodÄ tika kodÄti ar UTF-C par 60% labÄk nekÄ SCSU (iespÄjams, to kompakto alfabÄtu dÄļ).
AtseviŔķi piebildÄ«Å”u, ka bez SCSU ir arÄ« vÄl viens veids, kÄ kompakti attÄlot Unicode -
IespÄjamie uzlabojumi
Manis piedÄvÄtais algoritms pÄc konstrukcijas nav universÄls (iespÄjams, tieÅ”i Å”eit mani mÄrÄ·i visvairÄk atŔķiras no Unicode konsorcija mÄrÄ·iem). Es jau minÄju, ka tas tika izstrÄdÄts galvenokÄrt vienam uzdevumam (daudzvalodu vÄrdnÄ«cas glabÄÅ”anai prefiksu kokÄ), un dažas tÄs funkcijas var nebÅ«t piemÄrotas citiem uzdevumiem. Bet tas, ka tas nav standarts, var bÅ«t pluss - varat to viegli pÄrveidot atbilstoÅ”i savÄm vajadzÄ«bÄm.
PiemÄram, acÄ«mredzamÄ veidÄ jÅ«s varat atbrÄ«voties no stÄvokļa klÄtbÅ«tnes, veikt bezvalstnieku kodÄÅ”anu - vienkÄrÅ”i neatjauniniet mainÄ«gos offs
, auxOffs
Šø is21Bit
kodÄtÄjÄ un dekodÄtÄjÄ. Å ajÄ gadÄ«jumÄ nebÅ«s iespÄjams efektÄ«vi iepakot viena un tÄ paÅ”a alfabÄta rakstzÄ«mju secÄ«bas, taÄu bÅ«s garantija, ka viena un tÄ pati rakstzÄ«me vienmÄr tiek kodÄta ar vieniem un tiem paÅ”iem baitiem neatkarÄ«gi no konteksta.
TurklÄt jÅ«s varat pielÄgot kodÄtÄju noteiktai valodai, mainot noklusÄjuma stÄvokli - piemÄram, koncentrÄjoties uz tekstiem krievu valodÄ, sÄkumÄ iestatiet kodÄtÄju un dekodÄtÄju. offs = 0x0400
Šø auxOffs = 0
. Tas ir Ä«paÅ”i loÄ£iski bezvalsts režīma gadÄ«jumÄ. KopumÄ tas bÅ«s lÄ«dzÄ«gs vecÄ astoÅu bitu kodÄjuma izmantoÅ”anai, taÄu netiek noÅemta iespÄja pÄc vajadzÄ«bas ievietot rakstzÄ«mes no visa unikoda.
VÄl viens iepriekÅ” minÄtais trÅ«kums ir tÄds, ka lielajÄ UTF-C kodÄtÄ tekstÄ nav iespÄjams Ätri atrast rakstzÄ«mju robežu, kas ir vistuvÄk patvaļīgam baitam. Ja nogriežat pÄdÄjos, teiksim, 100 baitus no kodÄtÄ bufera, jÅ«s riskÄjat iegÅ«t atkritumus, ar kuriem neko nevarat izdarÄ«t. KodÄjums nav paredzÄts vairÄku gigabaitu žurnÄlu glabÄÅ”anai, taÄu kopumÄ to var labot. baits 0xBF
nekad nedrÄ«kst parÄdÄ«ties kÄ pirmais baits (bet var bÅ«t otrais vai treÅ”ais). TÄpÄc, kodÄjot, varat ievietot secÄ«bu 0xBF 0xBF 0xBF
ik, teiksim, 10 KB - tad, ja jÄatrod robeža, pietiks ar izvÄlÄto gabalu skenÄt, lÄ«dz tiks atrasts lÄ«dzÄ«gs marÄ·ieris. Sekojot pÄdÄjam 0xBF
tiek garantÄts, ka tas ir varoÅa sÄkums. (DekodÄjot, Ŕī trÄ«s baitu secÄ«ba, protams, bÅ«s jÄignorÄ.)
SummÄjot
Ja esat izlasÄ«jis tik tÄlu, apsveicam! Es ceru, ka jÅ«s, tÄpat kÄ es, uzzinÄjÄt kaut ko jaunu (vai atsvaidzinÄjÄt atmiÅu) par Unicode struktÅ«ru.
Demo lapa. Ebreju valodas piemÄrs parÄda priekÅ”rocÄ«bas gan salÄ«dzinÄjumÄ ar UTF-8, gan SCSU.
IepriekÅ” aprakstÄ«to pÄtÄ«jumu nevajadzÄtu uzskatÄ«t par standartu iejaukÅ”anos. TomÄr kopumÄ esmu apmierinÄts ar sava darba rezultÄtiem, tÄpÄc esmu apmierinÄts ar tiem
Visbeidzot, es vÄlreiz pievÄrsÄ«Å”u uzmanÄ«bu gadÄ«jumiem, kad tiek izmantots UTF-C nav tÄ vÄrts:
- Ja jÅ«su rindas ir pietiekami garas (no 100 lÄ«dz 200 rakstzÄ«mÄm). Å ajÄ gadÄ«jumÄ jums vajadzÄtu padomÄt par tÄdu saspieÅ”anas algoritmu izmantoÅ”anu kÄ deflÄcija.
- Ja tev vajag ASCII caurspÄ«dÄ«gums, tas ir, jums ir svarÄ«gi, lai kodÄtÄs sekvences nesatur ASCII kodus, kas nebija sÄkotnÄjÄ virknÄ. To var novÄrst, ja, mijiedarbojoties ar treÅ”Äs puses API (piemÄram, strÄdÄjot ar datu bÄzi), kodÄÅ”anas rezultÄtu nododat kÄ abstraktu baitu kopu, nevis kÄ virknes. PretÄjÄ gadÄ«jumÄ jÅ«s riskÄjat iegÅ«t negaidÄ«tas ievainojamÄ«bas.
- Ja vÄlaties Ätri atrast rakstzÄ«mju robežas ar patvaļīgu nobÄ«di (piemÄram, ja ir bojÄta lÄ«nijas daļa). To var izdarÄ«t, bet tikai skenÄjot rindiÅu no sÄkuma (vai piemÄrojot iepriekÅ”ÄjÄ sadaÄ¼Ä aprakstÄ«to modifikÄciju).
- Ja nepiecieÅ”ams Ätri veikt darbÄ«bas ar virkÅu saturu (Ŕķirot tÄs, meklÄt tajÄs apakÅ”virknes, sasaistÄ«t). Tam vispirms ir jÄatÅ”ifrÄ virknes, tÄpÄc UTF-C Å”ajos gadÄ«jumos bÅ«s lÄnÄks nekÄ UTF-8 (bet ÄtrÄk nekÄ saspieÅ”anas algoritmi). TÄ kÄ viena un tÄ pati virkne vienmÄr tiek kodÄta vienÄdi, precÄ«zs dekodÄÅ”anas salÄ«dzinÄjums nav nepiecieÅ”ams, un to var veikt pa baitam.
Update: lietotÄjs
Avots: www.habr.com