Laing bisikleta: among gitipigan ang Unicode strings nga 30-60% nga mas compact kaysa UTF-8

Laing bisikleta: among gitipigan ang Unicode strings nga 30-60% nga mas compact kaysa UTF-8

Kung ikaw usa ka developer ug nag-atubang ka sa tahas sa pagpili sa usa ka pag-encode, nan ang Unicode hapit kanunay ang husto nga solusyon. Ang piho nga pamaagi sa representasyon nagdepende sa konteksto, apan kasagaran adunay usa ka unibersal nga tubag dinhi usab - UTF-8. Ang maayo nga butang bahin niini mao nga gitugotan ka nga magamit ang tanan nga mga karakter sa Unicode nga wala’y paggasto usab daghang byte sa kadaghanang kaso. Tinuod, para sa mga lengguwahe nga naggamit ug labaw pa sa Latin nga alpabeto, β€œdili kaayo” labing menos duha ka byte kada karakter. Makahimo ba kita og mas maayo nga dili na mobalik sa prehistoric encodings nga naglimite kanato ngadto sa 256 ka available nga mga karakter?

Sa ubos gisugyot ko nga pamilyar ang imong kaugalingon sa akong pagsulay nga tubagon kini nga pangutana ug ipatuman ang usa ka medyo yano nga algorithm nga nagtugot kanimo sa pagtipig sa mga linya sa kadaghanan nga mga sinultian sa kalibutan nga wala idugang ang redundancy nga naa sa UTF-8.

Disclaimer. Mohimo dayon kog pipila ka importanteng reserbasyon: ang gihulagway nga solusyon wala gitanyag isip usa ka unibersal nga kapuli sa UTF-8, kini angay lamang sa usa ka pig-ot nga listahan sa mga kaso (dugang pa niini sa ubos), ug sa bisan unsa nga kaso kinahanglan nga kini gamiton sa pagpakig-uban sa mga third-party nga mga API (nga wala gani mahibalo mahitungod niini). Kasagaran, ang mga algorithm sa pag-compress sa kinatibuk-ang katuyoan (pananglitan, deflate) angay alang sa compact nga pagtipig sa daghang mga volume sa data sa teksto. Dugang pa, naa sa proseso sa paghimo sa akong solusyon, nakit-an nako ang usa ka naglungtad nga sumbanan sa Unicode mismo, nga nagsulbad sa parehas nga problema - kini medyo labi ka komplikado (ug kanunay nga labi ka grabe), apan sa gihapon kini usa ka gidawat nga sumbanan, ug dili lang ibutang. dungan sa tuhod. Isulti ko nimo bahin niya.

Mahitungod sa Unicode ug UTF-8

Sa pagsugod, pipila ka mga pulong bahin sa kung unsa kini Unicode ΠΈ UTF-8.

Sama sa imong nahibal-an, ang 8-bit nga mga pag-encode kaniadto popular. Uban kanila, ang tanan yano ra: 256 nga mga karakter mahimong maihap sa mga numero gikan sa 0 hangtod 255, ug ang mga numero gikan sa 0 hangtod 255 klaro nga girepresentahan ingon usa ka byte. Kung mobalik kita sa sinugdanan, ang pag-encode sa ASCII hingpit nga limitado sa 7 ka bit, busa ang labing hinungdanon nga bit sa representasyon sa byte niini mao ang zero, ug kadaghanan sa mga 8-bit nga pag-encode nahiuyon niini (nagkalainlain ra sila sa "ibabaw" bahin, diin ang labing mahinungdanon nga bit mao ang usa).

Unsa ang kalainan sa Unicode gikan sa mga pag-encode ug ngano nga daghang mga piho nga representasyon ang kauban niini - UTF-8, UTF-16 (BE ug LE), UTF-32? Atong husayon ​​kini sa han-ay.

Ang sukaranan nga sumbanan sa Unicode naghulagway lamang sa mga sulat tali sa mga karakter (ug sa pipila ka mga kaso, indibidwal nga mga sangkap sa mga karakter) ug sa ilang mga numero. Ug adunay daghang posible nga mga numero sa kini nga sumbanan - gikan sa 0x00 sa 0x10FFFF (1 ka buok). Kung gusto namong ibutang ang usa ka numero sa ingon nga range ngadto sa usa ka variable, dili ang 114 o 112 bytes nga igo alang kanamo. Ug tungod kay ang among mga processor dili kaayo gidisenyo alang sa pagtrabaho nga adunay tulo ka byte nga mga numero, mapugos kami sa paggamit ug kutob sa 1 ka byte matag karakter! Kini mao ang UTF-2, apan tungod niini nga "pagkausik" nga kini nga format dili popular.

Maayo na lang, ang han-ay sa mga karakter sulod sa Unicode dili basta-basta. Ang ilang tibuok set gibahin ngadto sa 17 "mga eroplano", ang matag usa niini adunay 65536 (0x10000) "mga punto sa code" Ang konsepto sa usa ka "punto sa code" dinhi yano ra numero sa karakter, nga gi-assign niini sa Unicode. Apan, sama sa gihisgutan sa ibabaw, sa Unicode dili lamang ang mga indibidwal nga mga karakter ang giihap, kondili usab ang ilang mga sangkap ug mga marka sa serbisyo (ug usahay wala'y bisan unsa nga katumbas sa numero - tingali sa pagkakaron, apan alang kanato kini dili kaayo importante), busa kini mao ang mas husto sa kanunay makig-istorya ilabi mahitungod sa gidaghanon sa mga numero sa ilang kaugalingon, ug dili mga simbolo. Apan, sa mosunod, alang sa kamubo, kanunay nakong gamiton ang pulong nga "simbolo", nga nagpasabot sa termino nga "code point".

Laing bisikleta: among gitipigan ang Unicode strings nga 30-60% nga mas compact kaysa UTF-8
Unicode nga mga eroplano. Sama sa imong nakita, kadaghanan niini (mga eroplano 4 hangtod 13) wala pa magamit.

Ang labing katingad-an mao nga ang tanan nga panguna nga "pulp" nahimutang sa zero plane, kini gitawag nga "Basic Multilingual Plane". Kung ang usa ka linya adunay teksto sa usa sa mga modernong lengguwahe (lakip ang Intsik), dili ka molapas sa kini nga eroplano. Apan dili nimo maputol ang nahabilin nga Unicode - pananglitan, ang emoji kasagarang nahimutang sa katapusan sa sunod nga eroplano,"Dugang nga Multilingual nga Plano"(kini gikan sa 0x10000 sa 0x1FFFF). Mao nga gibuhat kini sa UTF-16: ang tanan nga mga karakter nahulog sa sulod Basic Multilingual Plane, gi-encode nga "as is" nga adunay katumbas nga duha ka byte nga numero. Bisan pa, ang pipila sa mga numero sa kini nga sakup wala gyud magpakita sa piho nga mga karakter, apan gipakita nga pagkahuman sa kini nga parisan sa mga byte kinahanglan naton tagdon ang lain - pinaagi sa paghiusa sa mga kantidad sa kini nga upat ka mga byte nga magkauban, makakuha kita usa ka numero nga naglangkob ang tibuok balido nga Unicode range. Kini nga ideya gitawag ug β€œsurrogate couples”—tingali nakadungog na ka bahin kanila.

Busa ang UTF-16 nagkinahanglan og duha o (sa talagsaon nga mga kaso) upat ka byte kada "code point". Kini mao ang mas maayo kay sa paggamit sa upat ka bytes sa tanang panahon, apan Latin (ug uban pang mga ASCII nga mga karakter) sa diha nga gi-encode niini nga paagi usik-usik sa katunga sa luna sa mga sero. Ang UTF-8 gidesinyo sa pagtul-id niini: Ang ASCII niini nag-okupar, sama kaniadto, usa lang ka byte; mga code gikan sa 0x80 sa 0x7FF - duha ka byte; gikan sa 0x800 sa 0xFFFF - tulo, ug gikan 0x10000 sa 0x10FFFF - upat. Sa usa ka bahin, ang Latin nga alpabeto nahimo nga maayo: ang pagkaangay sa ASCII mibalik, ug ang pag-apod-apod mas parehas nga "pagkaylap" gikan sa 1 hangtod 4 bytes. Apan ang mga alpabeto gawas sa Latin, alaut, wala makabenepisyo sa bisan unsang paagi kung itandi sa UTF-16, ug daghan karon ang nanginahanglan tulo ka byte imbis nga duha - ang gilay-on nga nasakup sa usa ka duha ka byte nga rekord nagkunhod sa 32 ka beses, nga adunay 0xFFFF sa 0x7FF, ug walay Intsik o, pananglitan, Georgian ang nalakip niini. Cyrillic ug lima pa ka mga alphabets - hurray - lucky, 2 bytes matag karakter.

Nganong mahitabo ni? Atong tan-awon kung giunsa ang UTF-8 nagrepresentar sa mga code sa karakter:
Laing bisikleta: among gitipigan ang Unicode strings nga 30-60% nga mas compact kaysa UTF-8
Direkta nga magrepresentar sa mga numero, ang mga bit nga gimarkahan sa simbolo gigamit dinhi x. Makita nga sa usa ka duha ka byte nga rekord adunay 11 lamang ka mga bit (gikan sa 16). Ang nag-unang mga bit dinhi adunay usa lamang ka auxiliary function. Sa kaso sa usa ka upat ka byte nga rekord, 21 sa 32 ka bits ang gigahin alang sa code point number - kini daw nga ang tulo ka byte (nga naghatag sa kinatibuk-an nga 24 bits) igo na, apan ang mga service marker mokaon og daghan.

Daotan ba kini? Dili gyud. Sa usa ka bahin, kung nag-atiman kami pag-ayo bahin sa wanang, kami adunay mga algorithm sa compression nga dali nga mapapas ang tanan nga sobra nga entropy ug redundancy. Sa laing bahin, ang tumong sa Unicode mao ang paghatag sa labing unibersal nga coding nga posible. Pananglitan, mahimo natong itugyan ang usa ka linya nga gi-encode sa UTF-8 sa pag-code nga kaniadto nagtrabaho lamang sa ASCII, ug dili mahadlok nga kini makakita og karakter gikan sa ASCII range nga sa pagkatinuod wala didto (human sa tanan, sa UTF-8 tanan. bytes sugod sa gikan sa zero bit - mao gayud kini ang ASCII). Ug kung kalit namong gusto nga putlon ang usa ka gamay nga ikog gikan sa usa ka dako nga hilo nga wala’y pag-decode niini gikan sa sinugdanan (o ibalik ang bahin sa kasayuran pagkahuman sa usa ka nadaot nga seksyon), dali alang kanamo nga makit-an ang offset kung diin nagsugod ang usa ka karakter (igo na. sa paglaktaw sa mga byte nga adunay gamay nga prefix 10).

Nganong nag-imbento man ug bag-o?

Sa samang higayon, usahay adunay mga sitwasyon nga ang mga algorithm sa compression sama sa deflate dili kaayo magamit, apan gusto nimo nga makab-ot ang compact storage sa mga string. Sa personal, nasugatan nako kini nga problema kung naghunahuna bahin sa pagtukod compressed prefix nga kahoy alang sa usa ka dako nga diksyonaryo nga naglakip sa mga pulong sa arbitraryong mga pinulongan. Sa usa ka bahin, ang matag pulong mubo kaayo, busa ang pag-compress niini dili epektibo. Sa laing bahin, ang pag-implementar sa kahoy nga akong gikonsiderar gidesinyo aron ang matag byte sa gitipigan nga hilo makamugna og bulag nga punoan sa kahoy, mao nga ang pagminus sa ilang gidaghanon mapuslanon kaayo. Sa akong library Az.js (Ingon sa pymorphy2, diin kini gibase) ang usa ka susama nga problema masulbad sa yano - mga string nga giputos DAWG-diksyonaryo, gitipigan didto sa maayong daan nga CP1251. Apan, ingon nga sayon ​​sabton, kini maayo alang lamang sa limitado nga alpabeto - ang usa ka linya sa Chinese dili madugang sa maong diksyonaryo.

Sa tinuud, gusto nako nga matikdan ang usa pa nga dili maayo nga nuance nga mitungha kung gigamit ang UTF-8 sa ingon nga istruktura sa datos. Ang hulagway sa ibabaw nagpakita nga kung ang usa ka karakter gisulat nga duha ka byte, ang mga bit nga may kalabutan sa numero niini dili moabut sa usa ka laray, apan gibulag sa usa ka parisan sa mga bit. 10 sa tunga-tunga: 110xxxxx 10xxxxxx. Tungod niini, kung ang ubos nga 6 ka bits sa ikaduhang byte moawas sa code sa karakter (ie, mahitabo ang usa ka transisyon 10111111 β†’ 10000000), unya ang unang byte usab mausab. Kini nahimo nga ang letra nga "p" gipaila sa mga byte 0xD0 0xBF, ug ang sunod nga "r" mao na 0xD1 0x80. Sa usa ka prefix nga kahoy, kini modala ngadto sa pagbahin sa ginikanan node ngadto sa duha - usa alang sa prefix 0xD0, ug usa pa alang sa 0xD1 (bisan tuod ang tibuok Cyrillic alphabet mahimong ma-encode lamang sa ikaduhang byte).

Unsa akong nakuha

Nag-atubang sa kini nga problema, nakahukom ako nga magpraktis sa pagdula nga adunay mga piraso, ug sa samang higayon mas pamilyar ang istruktura sa Unicode sa kinatibuk-an. Ang resulta mao ang UTF-C encoding format ("C" alang sa compact), nga mogasto ug dili mosobra sa 3 ka byte kada code point, ug kasagarang motugot kanimo sa paggasto lamang usa ka dugang nga byte alang sa tibuok nga na-encode nga linya. Nagdala kini sa kamatuoran nga sa daghang mga dili ASCII nga mga alpabeto ang ingon nga pag-encode nahimo 30-60% nga mas compact kaysa UTF-8.

Gipresentar nako ang mga pananglitan sa pagpatuman sa pag-encode ug pag-decode sa mga algorithm sa porma JavaScript ug Go librarya, libre nimo kining gamiton sa imong code. Apan hatagan gihapon nako og gibug-aton nga sa usa ka diwa kini nga format nagpabilin nga usa ka "bisikleta", ug dili ko girekomenda nga gamiton kini nga walay nahibal-an kung nganong kinahanglan nimo kini. Kini labaw pa sa usa ka eksperimento kaysa usa ka seryoso nga "pagpauswag sa UTF-8". Bisan pa, ang kodigo didto gisulat nga hapsay, mubo, nga adunay daghang mga komento ug pagsakup sa pagsulay.

Laing bisikleta: among gitipigan ang Unicode strings nga 30-60% nga mas compact kaysa UTF-8
Mga resulta sa pagsulay ug pagtandi sa UTF-8

Ako pud panid sa demo, diin mahimo nimong susihon ang pasundayag sa algorithm, ug dayon isulti ko kanimo ang labi pa bahin sa mga prinsipyo ug proseso sa pag-uswag niini.

Pagwagtang sa sobra nga mga bit

Gikuha nako ang UTF-8 isip basehan, siyempre. Ang una ug labing klaro nga butang nga mahimong usbon niini mao ang pagpakunhod sa gidaghanon sa mga service bit sa matag byte. Pananglitan, ang unang byte sa UTF-8 kanunay magsugod sa bisan hain 0, o uban sa 11 - usa ka prefix 10 Ang mosunod lang nga mga byte ang aduna niini. Ilisan nato ang prefix 11 sa 1, ug alang sa sunod nga mga byte atong tangtangon ang mga prefix sa hingpit. Unsay mahitabo?

0xxxxxxx β€” 1 ka byte
10xxxxxx xxxxxxxx - 2 ka byte
110xxxxx xxxxxxxx xxxxxxxx - 3 ka byte

Teka, asa ang upat ka byte nga rekord? Apan dili na kini gikinahanglan - sa pagsulat sa tulo ka byte, aduna na kitay 21 bits nga magamit ug kini igo na alang sa tanang numero hangtod sa 0x10FFFF.

Unsa ang atong gisakripisyo dinhi? Ang labing hinungdanon nga butang mao ang pag-ila sa mga utlanan sa karakter gikan sa usa ka arbitraryong lokasyon sa buffer. Dili kita makatudlo sa usa ka arbitraryong byte ug makit-an ang sinugdanan sa sunod nga karakter gikan niini. Kini usa ka limitasyon sa among format, apan sa praktis kini panagsa ra kinahanglanon. Kasagaran kita makahimo sa pagdagan pinaagi sa buffer gikan sa sinugdanan (ilabi na kon mahitungod sa mubo nga mga linya).

Ang sitwasyon nga adunay mga pinulongan nga naglangkob sa 2 bytes nahimo usab nga mas maayo: karon ang two-byte nga format naghatag sa usa ka hanay sa 14 bits, ug kini mga code hangtod sa 0x3FFF. Ang mga Intsik walay swerte (ang ilang mga karakter kasagaran gikan sa 0x4E00 sa 0x9FFF), apan ang mga taga-Georgia ug daghang uban pang mga tawo mas makalingaw - ang ilang mga sinultian mohaum usab sa 2 byte matag karakter.

Pagsulod sa estado sa encoder

Atong hunahunaon karon ang bahin sa mga kabtangan sa mga linya mismo. Ang diksyonaryo kasagaran adunay mga pulong nga gisulat sa mga karakter sa parehas nga alpabeto, ug kini tinuod usab alang sa daghang uban pang mga teksto. Maayo nga itudlo kini nga alpabeto kausa, ug dayon ipakita lamang ang numero sa letra sa sulod niini. Atong tan-awon kon ang paghan-ay sa mga karakter sa Unicode table makatabang kanato.

Sama sa gihisgutan sa ibabaw, ang Unicode gibahin sa eroplano 65536 nga mga code matag usa. Apan dili kini usa ka mapuslanon nga dibisyon (sama sa giingon na, kasagaran naa kita sa zero plane). Mas makaiikag mao ang division pinaagi sa mga bloke. Kini nga mga han-ay wala nay piho nga gitas-on, ug mas makahuluganon - isip usa ka lagda, ang matag usa naghiusa sa mga karakter gikan sa samang alpabeto.

Laing bisikleta: among gitipigan ang Unicode strings nga 30-60% nga mas compact kaysa UTF-8
Usa ka bloke nga adunay mga karakter sa alpabetong Bengali. Ikasubo, alang sa makasaysayanon nga mga hinungdan, kini usa ka pananglitan sa dili kaayo dasok nga pakete - 96 nga mga karakter ang gubot nga nagkatag sa 128 nga mga punto sa block code.

Ang mga sinugdanan sa mga bloke ug ang ilang mga gidak-on kanunay nga multiple sa 16 - kini gihimo alang lamang sa kasayon. Dugang pa, daghang mga bloke ang nagsugod ug natapos sa mga kantidad nga daghang mga 128 o bisan 256 - pananglitan, ang sukaranan nga Cyrillic nga alpabeto nagkuha 256 bytes gikan sa 0x0400 sa 0x04FF. Kini sayon ​​​​kaayo: kung atong tipigan ang prefix kausa 0x04, unya ang bisan unsang Cyrillic nga karakter mahimong isulat sa usa ka byte. Tinuod, niining paagiha mawad-an kita sa oportunidad nga makabalik sa ASCII (ug sa bisan unsang ubang mga karakter sa kinatibuk-an). Busa atong buhaton kini:

  1. Duha ka byte 10yyyyyy yxxxxxxx dili lamang nagpasabut sa usa ka simbolo nga adunay usa ka numero yyyyyy yxxxxxxx, apan usab pagbag-o kasamtangan nga alpabeto sa yyyyyy y0000000 (i.e. nahinumduman nato ang tanang mga tipik gawas sa pinakagamay nga importante 7 gamay);
  2. Usa ka byte 0xxxxxxx mao kini ang kinaiya sa kasamtangang alpabeto. Kinahanglan lang kini idugang sa offset nga among nahinumduman sa lakang 1. Samtang wala namo usba ang alpabeto, ang offset zero, mao nga among gipadayon ang pagkaangay sa ASCII.

Ingon usab alang sa mga code nga nanginahanglan 3 bytes:

  1. Tulo ka byte 110yyyyy yxxxxxxx xxxxxxxx nagpakita ug simbolo nga adunay numero yyyyyy yxxxxxxx xxxxxxxx, pagbag-o kasamtangan nga alpabeto sa yyyyyy y0000000 00000000 (nahinumdom sa tanan gawas sa mga batan-on 15 gamay), ug susiha ang kahon nga naa na kita karon dugay mode (kon usbon ang alpabeto balik sa double-byte nga usa, atong i-reset kini nga bandila);
  2. Duha ka byte 0xxxxxxx xxxxxxxx sa taas nga mode kini mao ang kinaiya sa kasamtangan nga alpabeto. Sa susama, atong idugang kini sa offset gikan sa lakang 1. Ang bugtong kalainan mao nga karon atong gibasa ang duha ka byte (tungod kay mibalhin kita niini nga mode).

Nindot paminawon: karon samtang kinahanglan namong i-encode ang mga karakter gikan sa parehas nga 7-bit Unicode range, mogasto kami og 1 extra byte sa sinugdanan ug total nga usa ka byte kada karakter.

Laing bisikleta: among gitipigan ang Unicode strings nga 30-60% nga mas compact kaysa UTF-8
Nagtrabaho gikan sa usa sa mga naunang bersyon. Kanunay na kini nga gipildi ang UTF-8, apan adunay lugar alang sa pag-uswag.

Unsa ang mas grabe? Una, kita adunay usa ka kondisyon, nga mao kasamtangan nga alphabet offset ug checkbox taas nga mode. Kini dugang nga naglimite kanamo: karon ang parehas nga mga karakter mahimong ma-encode nga lahi sa lainlaing mga konteksto. Ang pagpangita alang sa mga substrings, pananglitan, kinahanglan buhaton nga tagdon kini, ug dili lamang pinaagi sa pagtandi sa mga byte. Ikaduha, sa diha nga giusab namo ang alpabeto, kini nahimong dili maayo sa pag-encode sa mga karakter sa ASCII (ug kini dili lamang ang Latin nga alpabeto, kondili usab ang batakang punctuation, lakip ang mga luna) - kinahanglan nila nga usbon ang alpabeto pag-usab ngadto sa 0, nga mao, pag-usab usa ka dugang nga byte (ug dayon usa pa aron makabalik sa among panguna nga punto).

Ang usa ka alpabeto maayo, ang duha mas maayo

Atong sulayan nga usbon gamay ang atong gamay nga prefix, pagpislit sa usa pa sa tulo nga gihulagway sa ibabaw:

0xxxxxxx - 1 byte sa normal nga mode, 2 sa taas nga mode
11xxxxxx β€” 1 ka byte
100xxxxx xxxxxxxx - 2 ka byte
101xxxxx xxxxxxxx xxxxxxxx - 3 ka byte

Laing bisikleta: among gitipigan ang Unicode strings nga 30-60% nga mas compact kaysa UTF-8

Karon sa usa ka duha ka byte nga rekord adunay usa nga dili kaayo magamit nga bit - mga punto sa code hangtod sa 0x1FFF, ug dili 0x3FFF. Bisan pa, kini labi ka labi ka dako kaysa sa mga doble nga byte nga UTF-8 nga mga kodigo, ang kadaghanan sa kasagaran nga mga sinultian nahiangay gihapon, ang labing namatikdan nga pagkawala nawala. hiragana ΠΈ katakana, naguol ang mga Hapon.

Unsa kining bag-ong code? 11xxxxxx? Kini usa ka gamay nga "stash" nga adunay gidak-on nga 64 nga mga karakter, nagpuno sa among panguna nga alpabeto, mao nga gitawag nako kini nga auxiliary (tabang) alpabeto. Kon atong ibalhin ang kasamtangan nga alpabeto, usa ka piraso sa karaang alpabeto mahimong auxiliary. Pananglitan, mibalhin kami gikan sa ASCII ngadto sa Cyrillic - ang stash karon adunay 64 ka karakter nga adunay sulod Latin nga alpabeto, numero, luna ug koma (labing kanunay nga pagsal-ot sa dili ASCII nga mga teksto). Balik sa ASCII - ug ang nag-unang bahin sa Cyrillic nga alpabeto mahimong auxiliary nga alpabeto.

Salamat sa pag-access sa duha ka mga alpabeto, mahimo namong madumala ang daghang mga teksto nga adunay gamay nga gasto sa pagbalhin sa mga alpabeto (ang punctuation kasagarang modala ngadto sa pagbalik sa ASCII, apan pagkahuman niana makakuha kami daghang dili ASCII nga mga karakter gikan sa dugang nga alpabeto, nga wala pagbalhin pag-usab).

Bonus: prefixing sa sub-alphabet 11xxxxxx ug pagpili sa inisyal nga offset niini 0xC0, nakuha namo ang partial compatibility sa CP1252. Sa laing pagkasulti, daghan (apan dili tanan) mga teksto sa Kasadpang Uropa nga gi-encode sa CP1252 ang parehas nga hitsura sa UTF-C.

Dinhi, bisan pa, usa ka kalisud ang mitungha: kung giunsa pagkuha ang usa ka auxiliary gikan sa panguna nga alpabeto? Mahimo nimong biyaan ang parehas nga offset, apan - sayang - dinhi ang istruktura sa Unicode nagdula na batok kanamo. Kasagaran ang panguna nga bahin sa alpabeto wala sa sinugdanan sa bloke (pananglitan, ang kapital sa Russia nga "A" adunay code 0x0410, bisan tuod ang Cyrillic block nagsugod sa 0x0400). Busa, sa pagkuha sa unang 64 ka mga karakter ngadto sa stash, kita mahimong mawad-an sa access sa ikog nga bahin sa alpabeto.

Aron masulbad kini nga problema, mano-mano ko nga miagi sa pipila ka mga bloke nga katumbas sa lainlaing mga pinulongan, ug gipiho ang offset sa auxiliary nga alpabeto sulod sa nag-unang usa alang kanila. Ang Latin nga alpabeto, isip usa ka eksepsiyon, sa kasagaran gi-reorder sama sa base64.

Laing bisikleta: among gitipigan ang Unicode strings nga 30-60% nga mas compact kaysa UTF-8

Katapusan nga mga paghikap

Hunahunaon nato kung asa pa ta makapauswag sa usa ka butang.

Timan-i nga ang format 101xxxxx xxxxxxxx xxxxxxxx nagtugot kanimo sa pag-encode sa mga numero hangtod sa 0x1FFFFF, ug ang Unicode matapos sa sayo pa, sa 0x10FFFF. Sa laing pagkasulti, ang katapusang code point irepresentar isip 10110000 11111111 11111111. Busa, makaingon kita nga kon ang unang byte anaa sa porma 1011xxxx (Asa xxxx labaw pa sa 0), unya lain ang gipasabot niini. Pananglitan, mahimo nimong idugang ang laing 15 ka mga karakter didto nga kanunay nga magamit alang sa pag-encode sa usa ka byte, apan nakahukom ko nga buhaton kini nga lahi.

Atong tan-awon ang mga bloke sa Unicode nga nanginahanglan tulo ka byte karon. Sa panguna, sama sa nahisgotan na, kini ang mga karakter nga Intsik - apan lisud ang pagbuhat sa bisan unsa uban kanila, adunay 21 ka libo niini. Apan ang hiragana ug katakana milupad usab didto - ug dili na kaayo daghan kanila, wala pay duha ka gatos. Ug, tungod kay nahinumduman namon ang mga Hapon, adunay usab mga emojis (sa tinuud, nagkatibulaag sila sa daghang mga lugar sa Unicode, apan ang mga nag-unang bloke naa sa sakup. 0x1F300 - 0x1FBFF). Kung gihunahuna nimo ang kamatuoran nga karon adunay mga emojis nga gitigum gikan sa daghang mga punto sa code sa usa ka higayon (pananglitan, ang emoji ‍‍‍Laing bisikleta: among gitipigan ang Unicode strings nga 30-60% nga mas compact kaysa UTF-8 naglangkob sa ingon ka daghan sa 7 code!), Unya kini mahimong usa ka bug-os nga kaulaw sa paggasto sa tulo ka bytes sa matag usa (7Γ—3 = 21 bytes alang sa alang sa usa ka icon, usa ka nightmare).

Busa, mopili mig pipila ka pinili nga mga han-ay nga katumbas sa emoji, hiragana ug katakana, i-numero kini ngadto sa usa ka padayon nga listahan ug i-encode kini isip duha ka byte imbes nga tulo:

1011xxxx xxxxxxxx

Nindot: ang nahisgutan nga emojiLaing bisikleta: among gitipigan ang Unicode strings nga 30-60% nga mas compact kaysa UTF-8, nga gilangkuban sa 7 nga mga punto sa kodigo, nagkuha ug 8 ka byte sa UTF-25, ug gihaum namon kini 14 (eksaktong duha ka byte alang sa matag code point). Pinaagi sa dalan, si Habr nagdumili sa paghilis niini (sa karaan ug sa bag-ong editor), mao nga kinahanglan nakong isal-ot kini sa usa ka hulagway.

Atong sulayan nga ayohon ang usa pa ka problema. Sa atong nahinumduman, ang batakang alpabeto mao ang esensya taas nga 6 bit, nga atong ibutang sa hunahuna ug ipapilit ang code sa matag sunod nga decoded nga simbolo. Sa kaso sa Chinese nga mga karakter nga anaa sa block 0x4E00 - 0x9FFF, kini bisan gamay nga 0 o 1. Dili kaayo kombenyente: kinahanglan naton kanunay nga ibalhin ang alpabeto taliwala niining duha nga mga kantidad (ie paggasto og tulo ka byte). Apan timan-i nga sa taas nga mode, gikan sa code mismo mahimo natong ibawas ang gidaghanon sa mga karakter nga atong gi-encode gamit ang mubo nga mode (pagkahuman sa tanan nga mga limbong nga gihulagway sa ibabaw, kini mao ang 10240) - unya ang han-ay sa mga hieroglyph mobalhin ngadto sa 0x2600 - 0x77FF, ug niini nga kaso, sa tibuok niining tibuok nga han-ay, ang labing mahinungdanon nga 6 bits (gikan sa 21) mahimong katumbas sa 0. Busa, ang mga han-ay sa hieroglyphs mogamit ug duha ka byte kada hieroglyph (nga mao ang kamalaumon alang sa usa ka dako nga range), nga walay hinungdan sa mga switch sa alphabet.

Alternatibong solusyon: SCSU, BOCU-1

Ang mga eksperto sa Unicode, nga bag-o lang nagbasa sa ulohan sa artikulo, lagmit nga magdali sa pagpahinumdom kanimo nga direkta sa mga sumbanan sa Unicode adunay Standard Compression Scheme para sa Unicode (SCSU), nga naghulagway sa pamaagi sa pag-encode nga susama kaayo sa gihulagway sa artikulo.

Giangkon nako nga matinud-anon: Nahibal-an ko ang bahin sa pagkaanaa niini pagkahuman nga naunlod ako pag-ayo sa pagsulat sa akong desisyon. Kung nahibal-an ko kini gikan sa sinugdanan, tingali gisulayan nako ang pagsulat sa usa ka pagpatuman imbis nga maghimo sa akong kaugalingon nga pamaagi.

Ang nakapaikag kay ang SCSU naggamit ug mga ideya nga susama kaayo sa akong nahimo sa akong kaugalingon (imbes nga konsepto sa β€œmga alpabeto” ilang gigamit ang β€œmga bintana”, ug mas daghan pa niini ang anaa kay sa akoa). Sa parehas nga oras, kini nga format adunay mga disbentaha usab: mas duol kini sa mga algorithm sa compression kaysa sa mga pag-encode. Sa partikular, ang sumbanan naghatag daghang mga pamaagi sa representasyon, apan wala isulti kung giunsa pagpili ang labing kamalaumon - alang niini, ang encoder kinahanglan mogamit usa ka matang sa heuristics. Sa ingon, ang usa ka SCSU encoder nga nagpatunghag maayong pagputos mahimong mas komplikado ug mas hago kay sa akong algorithm.

Alang sa pagtandi, gibalhin nako ang usa ka medyo yano nga pagpatuman sa SCSU sa JavaScript - sa mga termino sa gidaghanon sa code kini nahimo nga ikatandi sa akong UTF-C, apan sa pipila ka mga kaso ang resulta napulo ka porsyento nga mas grabe (usahay kini mahimong molapas niini, apan dili kaayo). Pananglitan, ang mga teksto sa Hebreohanon ug Grego gi-encode sa UTF-C 60% mas maayo kay sa SCSU (tingali tungod sa ilang mga compact alphabets).

Sa bulag, akong idugang nga gawas sa SCSU adunay lain usab nga paagi sa pagrepresentar sa Unicode - BOCU-1, apan kini nagtumong sa pagkaangay sa MIME (nga wala nako kinahanglana) ug nagkuha ug gamay nga lahi nga pamaagi sa pag-encode. Wala nako masusi ang pagka-epektibo niini, apan alang kanako dili kini lagmit nga mas taas kaysa SCSU.

Posible nga mga pag-uswag

Ang algorithm nga akong gipresentar dili unibersal pinaagi sa disenyo (kini tingali kung diin ang akong mga katuyoan naglainlain gikan sa mga katuyoan sa Unicode Consortium). Nahisgotan na nako nga kini gimugna alang sa usa ka buluhaton (pagtipig sa usa ka multilingguwal nga diksyonaryo sa usa ka prefix tree), ug ang pipila sa mga bahin niini mahimong dili haum sa ubang mga buluhaton. Apan ang kamatuoran nga kini dili usa ka sumbanan mahimong usa ka plus - dali ra nimo kini usbon aron mohaum sa imong mga panginahanglan.

Pananglitan, sa klaro nga paagi nga imong mapapahawa ang presensya sa estado, paghimo og stateless coding - ayaw lang pag-update sa mga variable offs, auxOffs ΠΈ is21Bit sa encoder ug decoder. Sa kini nga kaso, dili posible nga epektibo nga mag-pack sa mga han-ay sa mga karakter sa parehas nga alpabeto, apan adunay garantiya nga ang parehas nga karakter kanunay nga gi-encode sa parehas nga mga byte, bisan unsa pa ang konteksto.

Dugang pa, mahimo nimong ipahiangay ang encoder sa usa ka piho nga sinultian pinaagi sa pagbag-o sa default nga estado - pananglitan, pag-focus sa mga teksto sa Russia, ibutang ang encoder ug decoder sa sinugdanan. offs = 0x0400 ΠΈ auxOffs = 0. Kini labi ka makatarunganon sa kaso sa stateless mode. Sa kinatibuk-an, susama kini sa paggamit sa daan nga walo ka bit nga pag-encode, apan dili makuha ang abilidad sa pagsal-ot sa mga karakter gikan sa tanan nga Unicode kung gikinahanglan.

Ang laing disbentaha nga gihisgutan sa sayo pa mao nga sa dagkong teksto nga gi-encode sa UTF-C walay dali nga paagi sa pagpangita sa utlanan sa karakter nga labing duol sa usa ka arbitraryong byte. Kung putlon nimo ang katapusan, ingnon ta, 100 bytes gikan sa gi-encode nga buffer, peligro ka nga makakuha og basura nga dili nimo mahimo. Ang pag-encode wala gidisenyo alang sa pagtipig sa mga multi-gigabyte nga mga troso, apan sa kinatibuk-an kini mahimong matul-id. Byte 0xBF kinahanglan dili gayud makita isip unang byte (apan mahimong ikaduha o ikatulo). Busa, sa pag-encode, mahimo nimong isulod ang han-ay 0xBF 0xBF 0xBF matag, ingnon, 10 KB - unya, kung kinahanglan nimo pangitaon ang usa ka utlanan, igo na ang pag-scan sa napili nga piraso hangtod makit-an ang usa ka parehas nga marka. Pagsunod sa katapusan 0xBF gigarantiyahan nga mahimong sinugdanan sa usa ka karakter. (Kung mag-decode, kini nga han-ay sa tulo ka byte, siyempre, kinahanglan nga ibalewala.)

Sa pag-summarize

Kung nabasa nimo kini hangtod karon, pahalipay! Nanghinaut ko nga ikaw, sama kanako, nakakat-on og bag-o (o gipa-refresh ang imong panumduman) mahitungod sa istruktura sa Unicode.

Laing bisikleta: among gitipigan ang Unicode strings nga 30-60% nga mas compact kaysa UTF-8
Demo nga panid. Ang pananglitan sa Hebreohanon nagpakita sa mga bentaha sa UTF-8 ug SCSU.

Ang gihulagway sa ibabaw nga panukiduki dili angay isipon nga usa ka paglapas sa mga sumbanan. Bisan pa, sa kasagaran kontento ako sa mga resulta sa akong trabaho, busa nalipay ako kanila bahin: pananglitan, ang minified JS library motimbang lang ug 1710 bytes (ug walay dependency, siyempre). Sama sa akong gihisgutan sa ibabaw, ang iyang trabaho makita sa panid sa demo (adunay usa usab ka hugpong sa mga teksto diin mahimo kini itandi sa UTF-8 ug SCSU).

Sa katapusan, sa makausa pa akong ipunting ang atensyon sa mga kaso diin gigamit ang UTF-C dili kini takus:

  • Kung ang imong mga linya igo ang gitas-on (gikan sa 100-200 nga mga karakter). Sa kini nga kaso, kinahanglan nimong hunahunaon ang paggamit sa mga algorithm sa compression sama sa deflate.
  • Kung kinahanglan nimo Transparency sa ASCII, sa ato pa, importante para nimo nga ang na-encode nga mga han-ay walay mga ASCII code nga wala sa orihinal nga string. Ang panginahanglan alang niini mahimong malikayan kung, kung nakig-interact sa mga third-party nga API (pananglitan, nagtrabaho sa usa ka database), imong gipasa ang resulta sa pag-encode isip abstract nga set sa bytes, ug dili isip mga string. Kung dili, peligro ka nga makakuha sa wala damha nga mga kahuyangan.
  • Kung gusto nimo nga dali nga makit-an ang mga utlanan sa karakter sa usa ka arbitraryong offset (pananglitan, kung ang bahin sa usa ka linya nadaot). Mahimo kini, apan pinaagi lamang sa pag-scan sa linya gikan sa sinugdanan (o paggamit sa pagbag-o nga gihulagway sa miaging seksyon).
  • Kung kinahanglan nimo nga dali nga himuon ang mga operasyon sa sulud sa mga kuwerdas (pagsunud-sunod kini, pangitaa ang mga substrings sa kanila, pagdugtong). Nagkinahanglan kini og mga kuwerdas nga ma-decode una, mao nga ang UTF-C mahimong mas hinay kaysa UTF-8 niining mga kasoha (apan mas paspas kay sa compression algorithm). Tungod kay ang parehas nga hilo kanunay nga gi-encode sa parehas nga paagi, ang eksaktong pagtandi sa pag-decode dili kinahanglan ug mahimo sa usa ka byte-by-byte nga basehan.

update: ang tiggamit Tyomitch sa mga komento sa ubos Nag-post og graph nga nagpasiugda sa mga limitasyon sa paggamit sa UTF-C. Gipakita niini nga ang UTF-C mas episyente kay sa usa ka general-purpose compression algorithm (usa ka variation sa LZW) basta ang giputos nga string mas mubo. ~140 ka karakter (bisan pa niana, akong namatikdan nga ang pagtandi gihimo sa usa ka teksto; alang sa ubang mga pinulongan ang resulta mahimong magkalahi).
Laing bisikleta: among gitipigan ang Unicode strings nga 30-60% nga mas compact kaysa UTF-8

Source: www.habr.com

Idugang sa usa ka comment