Baidhsagal eile: bidh sinn a’ stòradh sreangan Unicode 30-60% nas toinnte na UTF-8

Baidhsagal eile: bidh sinn a’ stòradh sreangan Unicode 30-60% nas toinnte na UTF-8

Ma tha thu nad leasaiche agus gu bheil an obair agad còdachadh a thaghadh, is e Unicode cha mhòr an-còmhnaidh am fuasgladh ceart. Tha an dòigh riochdachaidh sònraichte an urra ris a’ cho-theacsa, ach mar as trice tha freagairt uile-choitcheann an seo cuideachd - UTF-8. Is e an rud math mu dheidhinn gu bheil e a’ leigeil leat a h-uile caractar Unicode a chleachdadh gun chaitheamh cus tòrr bytes sa mhòr-chuid de chùisean. Fìor, airson cànanan a chleachdas barrachd air dìreach an aibideil Laideann, tha “chan eil cus” co-dhiù dà byte gach caractar. An urrainn dhuinn dèanamh nas fheàrr gun a bhith a’ tilleadh gu còdachaidhean ro-eachdraidheil a tha gar cuingealachadh gu dìreach 256 caractar a tha rim faighinn?

Gu h-ìosal tha mi a 'moladh a bhith eòlach air an oidhirp agam a' cheist seo a fhreagairt agus algairim coimeasach sìmplidh a chur an gnìomh a leigeas leat loidhnichean a stòradh anns a 'mhòr-chuid de chànanan an t-saoghail gun a bhith a' cur ris an dìth obrach a tha ann an UTF-8.

Àicheadh. Nì mi beagan teagamhan cudromach sa bhad: chan eil am fuasgladh a chaidh a mhìneachadh air a thabhann mar àite uile-choitcheann airson UTF-8, chan eil e freagarrach ach ann an liosta chumhang de chùisean (barrachd orra gu h-ìosal), agus cha bu chòir a chleachdadh ann an suidheachadh sam bith airson eadar-obrachadh le APIan treas-phàrtaidh (nach eil eadhon eòlach air). Mar as trice, tha algorithms teannachaidh adhbhar coitcheann (mar eisimpleir, deflate) freagarrach airson stòradh teann de mhòran dàta teacsa. A bharrachd air an sin, mar-thà ann am pròiseas cruthachadh mo fhuasgladh, lorg mi inbhe a th’ ann mar-thà ann an Unicode fhèin, a dh ’fhuasglas an aon dhuilgheadas - tha e rudeigin nas toinnte (agus gu tric nas miosa), ach fhathast tha e na inbhe ris an deach gabhail, agus chan ann dìreach air a chuir. còmhla air an glùin. Innsidh mi dhut mu dheidhinn cuideachd.

Mu Unicode agus UTF-8

Airson tòiseachadh, beagan fhaclan mu dheidhinn dè a th’ ann Unicode и UTF-8.

Mar a tha fios agad, b’ àbhaist còdachadh 8-bit a bhith mòr-chòrdte. Còmhla riutha, bha a h-uile dad sìmplidh: faodar 256 caractar a bhith air an àireamhachadh le àireamhan bho 0 gu 255, agus faodar àireamhan bho 0 gu 255 a riochdachadh gu follaiseach mar aon bheart. Ma thèid sinn air ais chun fhìor thoiseach, tha an còdachadh ASCII gu tur cuingealaichte ri 7 pìosan, agus mar sin is e neoni am pìos as cudromaiche san riochdachadh byte aige, agus tha a’ mhòr-chuid de chòdachaidhean 8-bit co-chòrdail ris (chan eil iad eadar-dhealaichte ach anns an “uachdrach” pàirt, far a bheil am pìos as cudromaiche aon).

Ciamar a tha Unicode eadar-dhealaichte bho na còdachaidhean sin agus carson a tha uimhir de riochdachaidhean sònraichte co-cheangailte ris - UTF-8, UTF-16 (BE agus LE), UTF-32? Leig leinn a rèiteachadh ann an òrdugh.

Chan eil an inbhe Unicode bunaiteach a’ toirt cunntas ach air a’ chonaltradh eadar caractaran (agus ann an cuid de chùisean, co-phàirtean fa leth de charactaran) agus na h-àireamhan aca. Agus tha mòran àireamhan comasach anns an ìre seo - bho 0x00 gu 0x10FFFF (1 pìosan). Nam biodh sinn airson àireamh a chuir ann an leithid de raon ann an caochladair, cha bhiodh 114 no 112 bytes gu leòr dhuinn. Agus leis nach eil na pròiseasairean againn air an dealbhadh gu mòr airson a bhith ag obair le àireamhan trì-byte, dh’ fheumadh sinn uimhir ri 1 bytes gach caractar a chleachdadh! Is e seo UTF-2, ach tha e dìreach air sgàth an “sgudal” seo nach eil fèill mhòr air a’ chruth seo.

Gu fortanach, chan eil òrdugh nan caractaran taobh a-staigh Unicode air thuaiream. Tha an seata gu lèir aca air a roinn ann an 17 "plèanaichean", anns gach fear dhiubh tha 65536 (0x10000) «puingean còd" Tha bun-bheachd “puing còd” an seo gu sìmplidh àireamh caractar, air a shònrachadh dha le Unicode. Ach, mar a chaidh ainmeachadh gu h-àrd, ann an Unicode chan e a-mhàin gu bheil caractaran fa leth air an àireamhachadh, ach cuideachd na co-phàirtean agus na comharran seirbheis aca (agus uaireannan chan eil dad idir a’ freagairt ris an àireamh - is dòcha aig an àm seo, ach dhuinne chan eil seo cho cudromach), mar sin tha e nas ceart an-còmhnaidh bruidhinn gu sònraichte mun àireamh àireamhan fhèin, agus chan e samhlaidhean. Ach, anns na leanas, air sgàth giorrad, cleachdaidh mi am facal “samhla”, a’ ciallachadh an teirm “puing còd”.

Baidhsagal eile: bidh sinn a’ stòradh sreangan Unicode 30-60% nas toinnte na UTF-8
Planaichean Unicode. Mar a chì thu, tha a 'mhòr-chuid dheth (planaichean 4 gu 13) fhathast gun chleachdadh.

Is e an rud as iongantaiche gu bheil a h-uile prìomh “pulp” na laighe anns an itealan neoni, is e “Plèana bunaiteach ioma-chànanach". Ma tha teacsa ann an loidhne ann an aon de na nuadh-chànanan (Sìneach nam measg), cha tèid thu seachad air a' phlèana seo. Ach chan urrainn dhut an còrr de Unicode a ghearradh dheth nas motha - mar eisimpleir, tha emoji sa mhòr-chuid suidhichte aig deireadh na an ath itealan,"Plèana ioma-chànanach a bharrachd"(tha e a’ leudachadh bho 0x10000 gu 0x1FFFF). Mar sin bidh UTF-16 a’ dèanamh seo: a h-uile caractar a’ tuiteam a-staigh Plèana bunaiteach ioma-chànanach, air an còdachadh “mar a tha” le àireamh dà-byte co-fhreagarrach. Ach, chan eil cuid de na h-àireamhan san raon seo a’ comharrachadh caractaran sònraichte idir, ach tha iad a’ nochdadh gum feum sinn beachdachadh air fear eile às deidh a’ phaidhir bytes seo - le bhith a’ cothlamadh luachan nan ceithir bytes sin còmhla, gheibh sinn àireamh a tha a’ còmhdach an raon dligheach Unicode gu lèir. Canar “càraidean ionaid” ris a’ bheachd seo - is dòcha gu bheil thu air cluinntinn mun deidhinn.

Mar sin feumaidh UTF-16 dà no (ann an cùisean gu math tearc) ceithir bytes gach “puing còd”. Tha seo nas fheàrr na bhith a’ cleachdadh ceithir bytes fad na h-ùine, ach tha Laideann (agus caractaran ASCII eile) nuair a thèid a chòdachadh san dòigh seo a’ caitheamh leth an àite air neamhan. Tha UTF-8 air a dhealbhadh gus seo a cheartachadh: chan eil ASCII ann, mar a bha e roimhe, ach aon byte; còdan bho 0x80 gu 0x7FF - dà bytes; bho 0x800 gu 0xFFFF — tri, agus o 0x10000 gu 0x10FFFF - ceithir. Air an aon làimh, tha an aibideil Laideann air fàs math: tha co-chòrdalachd le ASCII air tilleadh, agus tha an cuairteachadh nas cothromaiche “air a sgaoileadh a-mach” bho 1 gu 4 bytes. Ach chan eil aibideil a bharrachd air Laideann, alas, a’ faighinn buannachd ann an dòigh sam bith an taca ri UTF-16, agus tha mòran a-nis ag iarraidh trì bytes an àite dhà - tha an raon a tha còmhdaichte le clàr dà-bhith air a dhol sìos 32 uair, le 0xFFFF gu 0x7FF, agus chan eil Sìonais no, mar eisimpleir, Seòrasach air an gabhail a-steach ann. Cirilis agus còig aibideil eile - hurray - fortanach, 2 byte gach caractar.

Carson a tha seo a’ tachairt? Chì sinn mar a tha UTF-8 a’ riochdachadh còdan caractar:
Baidhsagal eile: bidh sinn a’ stòradh sreangan Unicode 30-60% nas toinnte na UTF-8
Gu dìreach airson àireamhan a riochdachadh, thathas a’ cleachdadh pìosan comharraichte leis an t-samhla an seo x. Chithear nach eil ann an clàr dà-byte ach 11 pìosan mar sin (a-mach à 16). Chan eil ach gnìomh taiceil aig na prìomh phìosan an seo. A thaobh clàr ceithir-byte, tha 21 buillean a-mach à 32 air an riarachadh airson àireamh a’ phuing còd - bhiodh e coltach gum biodh trì bytes (a bheir 24 buillean gu h-iomlan) gu leòr, ach bidh comharran seirbheis ag ithe cus.

A bheil seo dona? Chan eil idir. Air an aon làimh, ma tha mòran dragh againn mu àite, tha algoirmean teannachaidh againn a dh’ fhaodas cuir às gu furasta an entropy agus call dreuchd a bharrachd. Air an làimh eile, b’ e amas Unicode an còdadh as uile-choitcheann a thoirt seachad. Mar eisimpleir, is urrainn dhuinn loidhne a chaidh a chòdachadh ann an UTF-8 a chuir an urra ri còd a bha ag obair le ASCII a-mhàin, agus na biodh eagal ort gum faic e caractar bhon raon ASCII nach eil ann dha-rìribh (às deidh a h-uile càil, ann an UTF-8 uile). bytes a’ tòiseachadh leis bhon ìre neoni - is e seo dìreach a th’ ann an ASCII). Agus ma tha sinn gu h-obann airson earball beag a ghearradh dheth bho shreang mhòr gun a bhith ga chòdachadh bhon fhìor thoiseach (no pàirt den fhiosrachadh a thoirt air ais às deidh earrann millte), tha e furasta dhuinn an cothromachadh a lorg far a bheil caractar a’ tòiseachadh (tha e gu leòr gus leum air bytes aig a bheil beagan ro-leasachan 10).

Carson an uairsin rudeigin ùr a chruthachadh?

Aig an aon àm, uaireannan bidh suidheachaidhean ann nuair nach eil algoirmean teannachaidh leithid deflate iomchaidh, ach tha thu airson stòradh teann de shreathan a choileanadh. Gu pearsanta, thachair mi ris an duilgheadas seo nuair a bha mi a’ smaoineachadh air togail craobh ro-leasachan teannaichte airson faclair mòr a’ gabhail a-steach faclan ann an cànanan neo-riaghailteach. Air an aon làimh, tha gach facal gu math goirid, agus mar sin bidh e neo-èifeachdach le teannachadh. Air an làimh eile, chaidh buileachadh na craoibhe a bheachdaich mi air a dhealbhadh gus am biodh gach byte den t-sreang a chaidh a stòradh a ’cruthachadh vertex craoibhe air leth, agus mar sin bha e glè fheumail an àireamh aca a lughdachadh. Anns an leabharlann agam Az.js (Mar ann an piorruidheachd 2, air a bheil e stèidhichte) faodar duilgheadas coltach ris a rèiteachadh gu sìmplidh - sreangan air am pacadh a-steach DAWG-dictionary, air a stòradh ann an deagh sheann CP1251. Ach, mar a tha furasta a thuigsinn, chan obraich seo gu math ach airson aibideil cuibhrichte - chan urrainnear loidhne ann an Sìonais a chur ri faclair mar sin.

Air leth, bu mhath leam a bhith mothachail air aon nuance mì-thlachdmhor eile a thig am bàrr nuair a bhios tu a ’cleachdadh UTF-8 ann an structar dàta mar sin. Tha an dealbh gu h-àrd a’ sealltainn, nuair a tha caractar air a sgrìobhadh mar dà byte, nach eil na pìosan co-cheangailte ris an àireamh aige a’ tighinn ann an sreath, ach gu bheil iad air an sgaradh le paidhir bhuillean 10 anns a 'mheadhan: 110xxxxx 10xxxxxx. Air sgàth seo, nuair a tha na pìosan 6 as ìsle den dàrna byte a’ dol thairis air a’ chòd caractar (ie, bidh eadar-ghluasad a’ tachairt 1011111110000000), an uairsin bidh a’ chiad byte ag atharrachadh cuideachd. Tha e coltach gu bheil an litir “p” air a chomharrachadh le bytes 0xD0 0xBF, agus tha an ath “r” mu thràth 0xD1 0x80. Ann an craobh ro-leasachan, tha seo a 'leantainn gu bhith a' roinneadh an nòta phàrant ann an dà - aon airson an ro-leasachan 0xD0, agus fear eile airson 0xD1 (ged nach gabhadh an aibideil Cyrillic gu lèir a chòdachadh ach leis an dàrna byte).

Dè fhuair mi

Leis an duilgheadas seo, chuir mi romham a bhith a’ cluich gheamannan le pìosan, agus aig an aon àm eòlas fhaighinn air structar Unicode gu h-iomlan. B’ e an toradh an cruth còdachadh UTF-C ("C" airson cùmhnant), a tha a 'cosg nach eil barrachd air 3 bytes gach puing còd, agus glè thric a' leigeil leat a chaitheamh a-mhàin aon byte a bharrachd airson an loidhne chòdaichte gu lèir. Tha seo a’ ciallachadh gu bheil a leithid de chòdachadh ann an iomadh aibideil neo-ASCII 30-60% nas toinnte na UTF-8.

Tha mi air eisimpleirean a thaisbeanadh de bhith a’ cur an gnìomh algorithms còdaidh is dì-chòdaidh san fhoirm Leabharlannan JavaScript agus Go, faodaidh tu an cleachdadh gu saor sa chòd agad. Ach cuiridh mi cuideam fhathast gu bheil an cruth seo fhathast na “baidhsagal”, agus chan eil mi a’ moladh a chleachdadh gun a bhith mothachail carson a tha feum agad air. Tha seo fhathast nas motha de dheuchainn na fìor “leasachadh UTF-8”. A dh'aindeoin sin, tha an còd an sin air a sgrìobhadh gu grinn, gu pongail, le àireamh mhòr de bheachdan agus còmhdach deuchainn.

Baidhsagal eile: bidh sinn a’ stòradh sreangan Unicode 30-60% nas toinnte na UTF-8
Toraidhean deuchainn agus coimeas le UTF-8

Rinn mi cuideachd duilleag demo, far an urrainn dhut measadh a dhèanamh air coileanadh an algairim, agus an uair sin innsidh mi dhuibh barrachd mu a phrionnsabalan agus pròiseas leasachaidh.

A 'toirt air falbh pìosan gun fheum

Ghabh mi UTF-8 mar bhunait, gu dearbh. Is e a’ chiad rud agus an rud as fhollaisiche a ghabhas atharrachadh ann an àireamh de phìosan seirbheis anns gach byte a lughdachadh. Mar eisimpleir, bidh a’ chiad byte ann an UTF-8 an-còmhnaidh a’ tòiseachadh leis an dàrna cuid 0, no le 11 - ro-leasachan 10 Chan eil ach na bytes a leanas aige. Cuireamaid an àite an ro-leasachan 11 air 1, agus airson an ath bytes bheir sinn air falbh na ro-leasachan gu tur. Dè thachras?

0xxxxxxx — 1 bhot
10xxxxxx xxxxxxxx — 2 byte
110xxxxx xxxxxxxx xxxxxxxx — 3 byte

Fuirich, càit a bheil an clàr ceithir-byte? Ach chan eil feum air tuilleadh - nuair a thathar a’ sgrìobhadh ann an trì bytes, tha 21 pìosan againn a-nis agus tha seo gu leòr airson a h-uile àireamh suas gu 0x10FFFF.

Dè a tha sinn air ìobairt a dhèanamh an seo? Is e an rud as cudromaiche lorg crìochan caractar bho àite neo-riaghailteach anns a 'bhufair. Chan urrainn dhuinn puing neo-riaghailteach a chomharrachadh agus toiseach an ath charactar a lorg bhuaithe. Tha seo na chuingealachadh air ar cruth, ach ann an cleachdadh is ann ainneamh a bhios feum air. Mar as trice bidh e comasach dhuinn ruith tron ​​​​bufair bhon fhìor thoiseach (gu sònraichte nuair a thig e gu loidhnichean goirid).

Tha an suidheachadh le cànanan còmhdaich le 2 bytes air fàs nas fheàrr cuideachd: a-nis tha an cruth dà-byte a’ toirt seachad raon de 14 pìosan, agus is iad sin còdan suas gu 0x3FFF. Tha na Sìonaich mì-shealbhach (tha na caractaran aca mar as trice a’ dol bho 0x4E00 gu 0x9FFF), ach tha barrachd spòrs aig Georgians agus mòran dhaoine eile - tha na cànanan aca cuideachd a’ freagairt air 2 byte gach caractar.

Cuir a-steach an staid encoder

A-nis smaoinich sinn air feartan nan loidhnichean fhèin. Mar as trice tha faclan sgrìobhte ann an caractaran den aon aibideil anns an fhaclair, agus tha seo fìor cuideachd airson mòran theacsaichean eile. Bhiodh e math an aibideil seo a chomharrachadh aon uair, agus an uairsin dìreach àireamh na litreach a tha na bhroinn a chomharrachadh. Feuch an cuidich sinn le rèiteachadh charactaran ann an clàr Unicode sinn.

Mar a chaidh ainmeachadh gu h-àrd, tha Unicode air a roinn na plèana Còdan 65536 gach. Ach chan e sgaradh glè fheumail a tha seo (mar a chaidh a ràdh mar-thà, mar as trice tha sinn anns an itealan neoni). Nas inntinniche tha an roinn le blocaichean. Chan eil fad stèidhichte aig na raointean sin tuilleadh, agus tha iad nas ciallaiche - mar riaghailt, bidh gach fear a’ cothlamadh charactaran bhon aon aibideil.

Baidhsagal eile: bidh sinn a’ stòradh sreangan Unicode 30-60% nas toinnte na UTF-8
Bloc anns a bheil caractaran den aibidil Bengali. Gu mì-fhortanach, airson adhbharan eachdraidheil, tha seo na eisimpleir de phacaid nach eil gu math dùmhail - tha caractaran 96 sgapte gu mì-mhodhail thairis air 128 puingean còd bloc.

Tha toiseach bhlocaichean agus na meudan aca an-còmhnaidh iomadan de 16 - tha seo air a dhèanamh dìreach airson goireasachd. A bharrachd air an sin, bidh mòran bhlocaichean a’ tòiseachadh agus a’ crìochnachadh air luachan a tha nan iomadan de 128 no eadhon 256 - mar eisimpleir, bidh an aibideil Cyrillic bunaiteach a’ toirt suas 256 bytes bho 0x0400 gu 0x04FF. Tha seo gu math goireasach: ma shàbhaileas sinn an ro-leasachan aon uair 0x04, an uairsin faodar caractar Cyrillic sam bith a sgrìobhadh ann an aon byte. Fìor, mar seo caillidh sinn an cothrom tilleadh gu ASCII (agus gu caractaran sam bith eile san fharsaingeachd). Mar sin bidh sinn a’ dèanamh seo:

  1. Dà byte 10yyyyyy yxxxxxxx chan e a-mhàin comharradh le àireamh yyyyyy yxxxxxxx, ach cuideachd atharrachadh aibidil làithreach air yyyyyy y0000000 (i.e. tha sinn a’ cuimhneachadh air a h-uile pìos ach a-mhàin an fheadhainn as cudromaiche Bit 7);
  2. Aon bhite 0xxxxxxx is e seo caractar na h-aibidil gnàthach. Feumaidh e dìreach a bhith air a chur ris an chothromachadh a chuimhnich sinn ann an ceum 1. Ged nach do dh'atharraich sinn an aibidil, tha an co-chothromachadh neoni, agus mar sin chùm sinn co-chòrdadh ri ASCII.

San aon dòigh airson còdan a dh’ fheumas 3 bytes:

  1. Trì bytes 110yyyyy yxxxxxxx xxxxxxxx comharraich samhla le àireamh yyyyyy yxxxxxxx xxxxxxxx, atharrachadh aibidil làithreach air yyyyyy y0000000 00000000 (cuimhnich air a h-uile càil ach an fheadhainn as òige Bit 15), agus thoir sùil air a’ bhogsa anns a bheil sinn a-nis fada modh (nuair a dh'atharraicheas sinn an aibidil air ais gu tè dà-bhith, ath-shuidhichidh sinn am bratach seo);
  2. Dà byte 0xxxxxxx xxxxxxxx ann am modh fada 's e caractar na h-aibidil làithreach a th' ann. San aon dòigh, bidh sinn ga chur ris leis a’ chothromachadh bho cheum 1. Is e an aon eadar-dhealachadh gu bheil sinn a-nis a’ leughadh dà bytes (seach gun do thionndaidh sinn chun mhodh seo).

A ’faireachdainn math: a-nis ged a dh’ fheumas sinn caractaran a chòdachadh bhon aon raon Unicode 7-bit, bidh sinn a ’caitheamh 1 byte a bharrachd aig an toiseach agus aon byte gu h-iomlan airson gach caractar.

Baidhsagal eile: bidh sinn a’ stòradh sreangan Unicode 30-60% nas toinnte na UTF-8
Ag obair bho aon de na dreachan nas tràithe. Tha e mar-thà gu tric a 'bualadh air UTF-8, ach tha àite ann fhathast airson leasachadh.

Dè tha nas miosa? An toiseach, tha suidheachadh againn, is e sin gnàthachadh na h-aibidil agus bogsa-seic modh fada. Tha seo gar cuingealachadh tuilleadh: a-nis faodar na h-aon charactaran a chòdachadh ann an dòigh eadar-dhealaichte ann an diofar cho-theacsan. Feumar rannsachadh airson fo-sreathan, mar eisimpleir, a’ gabhail seo a-steach, agus chan ann dìreach le bhith a’ dèanamh coimeas eadar bytes. San dàrna h-àite, cho luath ‘s a dh’ atharraich sinn an aibideil, dh ’fhàs e dona le còdachadh charactaran ASCII (agus chan e a-mhàin an aibideil Laideann a tha seo, ach cuideachd puingeachadh bunaiteach, a’ toirt a-steach àiteachan) - feumaidh iad an aibideil atharrachadh a-rithist gu 0, is e sin, a-rithist byte a bharrachd (agus an uairsin fear eile airson faighinn air ais chun phrìomh phuing againn).

Tha aon aibidil math, tha dhà nas fheàrr

Feuchaidh sinn ris na ro-leasachan beaga againn atharrachadh beagan, a’ brùthadh ann an aon eile dha na trì a tha air am mìneachadh gu h-àrd:

0xxxxxxx - 1 byte sa mhodh àbhaisteach, 2 ann am modh fada
11xxxxxx — 1 bhot
100xxxxx xxxxxxxx — 2 byte
101xxxxx xxxxxxxx xxxxxxxx — 3 byte

Baidhsagal eile: bidh sinn a’ stòradh sreangan Unicode 30-60% nas toinnte na UTF-8

A-nis ann an clàr dà-byte tha aon rud nas lugha ri fhaighinn - puingean còd suas gu 0x1FFFach chan eil 0x3FFF. Ach, tha e fhathast gu math nas motha na ann an còdan dùbailte UTF-8, tha na cànanan as cumanta fhathast a’ freagairt, tha an call as follaisiche air tuiteam a-mach hiragana и catakana, tha na Seapanach brònach.

Dè an còd ùr a tha seo? 11xxxxxx? Is e “stash” beag a tha seo de 64 caractar ann am meud, tha e a’ cur ris a’ phrìomh aibideil againn, agus mar sin thug mi taiceil dha (cuideachail) aibidil. Nuair a thionndaidheas sinn an aibidil gnàthach, bidh pìos den t-seann aibideil a’ fàs cuideachail. Mar eisimpleir, thionndaidh sinn bho ASCII gu Cyrillic - tha 64 caractar anns an stash a-nis anns a bheil Aibidil Laideann, àireamhan, àite agus cromag (cuir a-steach as trice ann an teacsaichean neo-ASCII). Tionndaidh air ais gu ASCII - agus bidh am prìomh phàirt den aibideil Cyrillic gu bhith na aibideil cuideachail.

Taing gu cothrom air dà aibidil, is urrainn dhuinn àireamh mhòr de theacsaichean a làimhseachadh le glè bheag de chosgaisean airson atharrachadh aibideil (mar as trice bidh puingeachadh a’ leantainn gu tilleadh gu ASCII, ach às deidh sin gheibh sinn mòran charactaran neo-ASCII bhon aibideil a bharrachd, às aonais ag atharrachadh a-rithist).

Bònas: ro-leasachan na fo-aibidil 11xxxxxx agus a 'taghadh a chothromachadh tùsail airson a bhith 0xC0, gheibh sinn co-chòrdalachd pàirt le CP1252. Ann am faclan eile, bidh mòran (ach chan eil a h-uile) de theacsaichean taobh an iar na Roinn Eòrpa air an còdachadh ann an CP1252 a’ coimhead an aon rud ann an UTF-C.

An seo, ge-tà, tha duilgheadas ag èirigh: ciamar a gheibhear fear cuideachaidh bhon phrìomh aibidil? Faodaidh tu an aon chothromachadh fhàgail, ach - mo thruaighe - an seo tha structar Unicode a’ cluich nar n-aghaidh mu thràth. Gu math tric chan eil prìomh phàirt na h-aibidil aig toiseach a 'bhloc (mar eisimpleir, tha an còd aig prìomh-bhaile na Ruis "A" 0x0410, ged a thòisicheas am bloc Cyrillic le 0x0400). Mar sin, às deidh dhuinn a’ chiad 64 caractaran a thoirt a-steach don stash, is dòcha gun caill sinn cothrom air pàirt earball na h-aibideil.

Gus an duilgheadas seo a cheartachadh, chaidh mi tro chuid de bhlocaichean le làimh a bha co-chosmhail ri diofar chànanan, agus shònraich mi co-chothromachadh na h-aibideil cuideachail taobh a-staigh a’ phrìomh fhear dhaibh. Chaidh an aibidil Laideann, mar eisgeachd, ath-òrdachadh sa chumantas mar base64.

Baidhsagal eile: bidh sinn a’ stòradh sreangan Unicode 30-60% nas toinnte na UTF-8

Suathadh deireannach

Feuch an smaoinich sinn mu dheireadh càite eile as urrainn dhuinn rudeigin a leasachadh.

Thoir an aire gu bheil an cruth 101xxxxx xxxxxxxx xxxxxxxx a’ leigeil leat àireamhan a chòdachadh suas gu 0x1FFFFF, agus tha Unicode a’ crìochnachadh na bu thràithe, aig 0x10FFFF. Ann am faclan eile, bidh am puing còd mu dheireadh air a riochdachadh mar 10110000 11111111 11111111. Mar sin, faodaidh sinn a ràdh ma tha a 'chiad byte den fhoirm 1011xxxx (Càite xxxx nas motha na 0), tha e a’ ciallachadh rudeigin eile. Mar eisimpleir, faodaidh tu caractaran 15 eile a chuir ris an sin a tha an-còmhnaidh rim faighinn airson còdachadh ann an aon byte, ach chuir mi romham a dhèanamh ann an dòigh eadar-dhealaichte.

Bheir sinn sùil air na blocaichean Unicode sin a dh’ fheumas trì bytes a-nis. Gu bunaiteach, mar a chaidh ainmeachadh roimhe, is e caractaran Sìneach a tha seo - ach tha e duilich dad a dhèanamh leotha, tha 21 mìle dhiubh ann. Ach bha hiragana agus katakana cuideachd ag itealaich ann - agus chan eil uimhir dhiubh ann tuilleadh, nas lugha na dà cheud. Agus, leis gu bheil cuimhne againn air na Seapanach, tha emojis ann cuideachd (gu dearbh, tha iad sgapte ann an iomadh àite ann an Unicode, ach tha na prìomh bhlocaichean san raon 0x1F300 - 0x1FBFF). Ma smaoinicheas tu air gu bheil a-nis emojis ann a tha air an cruinneachadh bho ghrunn phuingean còd aig an aon àm (mar eisimpleir, an emojiBaidhsagal eile: bidh sinn a’ stòradh sreangan Unicode 30-60% nas toinnte na UTF-8 air a dhèanamh suas de uimhir ri 7 còdan!), An uairsin bidh e na fhìor nàire trì bytes a chaitheamh air gach fear (7 × 3 = 21 bytes air sgàth aon ìomhaigh, trom-laighe).

Mar sin, bidh sinn a’ taghadh beagan raointean taghte a rèir emoji, hiragana agus katakana, gan ath-àireamhachadh ann an aon liosta leantainneach agus gan còdachadh mar dà bytes an àite trì:

1011xxxx xxxxxxxx

Sgoinneil: mar a chaidh ainmeachadh ‍‍🏫Baidhsagal eile: bidh sinn a’ stòradh sreangan Unicode 30-60% nas toinnte na UTF-8, air a dhèanamh suas de 7 puingean còd, a’ toirt 8 bytes ann an UTF-25, agus bidh sinn ga chuir a-steach 14 (dìreach dà byte airson gach puing còd). Air an t-slighe, dhiùlt Habr a chnàmh (an dà chuid san t-seann agus anns an deasaiche ùr), agus mar sin bha agam ri dealbh a chuir a-steach.

Feuchaidh sinn ri aon duilgheadas eile a rèiteachadh. Mar a chuimhnicheas sinn, tha an aibideil bunaiteach gu bunaiteach 6 pìosan àrd, a chumas sinn nar cuimhne agus a ghleidheas sinn ri còd gach ath shamhla dì-chòdaichte. Ann an cùis caractaran Sìneach a tha sa bhloc 0x4E00 - 0x9FFF, is e seo an dàrna cuid bit 0 no 1. Chan eil seo gu math goireasach: feumaidh sinn an aibideil atharrachadh gu cunbhalach eadar an dà luach seo (i.e. trì bytes a chaitheamh). Ach thoir an aire, anns a’ mhodh fhada, bhon chòd fhèin gun urrainn dhuinn an àireamh de charactaran a chòdaicheas sinn a thoirt air falbh a’ cleachdadh a’ mhodh ghoirid (às deidh a h-uile cleas a chaidh a mhìneachadh gu h-àrd, is e seo 10240) - an uairsin gluaisidh an raon hieroglyphs gu 0x2600 - 0x77FF, agus anns a 'chùis seo, air feadh an raoin seo gu lèir, bidh na pìosan 6 as cudromaiche (a-mach à 21) co-ionnan ri 0. Mar sin, cleachdaidh sreathan de hieroglyphs dà bytes gach hieroglyph (a tha freagarrach airson raon cho mòr), gun ag adhbhrachadh suidsichean aibideil.

Fuasglaidhean eile: SCSU, BOCU-1

Tha e glè choltach gun dèan eòlaichean Unicode, às deidh dhaibh tiotal an artaigil a leughadh, cabhag gus do chuir an cuimhne gu bheil gu dìreach am measg inbhean Unicode. Sgeama teannachaidh àbhaisteach airson Unicode (SCSU), a tha a’ toirt cunntas air dòigh còdaidh a tha glè choltach ris an fhear a tha air a mhìneachadh san artaigil.

Tha mi ag aideachadh gu h-onarach: dh’ ionnsaich mi mu dheidhinn a bhith ann dìreach às deidh dhomh a bhith air mo bhogadh gu mòr ann a bhith a’ sgrìobhadh mo cho-dhùnadh. Nam biodh fios agam mu dheidhinn bhon toiseach, is dòcha gum bithinn air feuchainn ri buileachadh a sgrìobhadh an àite a bhith a’ tighinn suas leis an dòigh-obrach agam fhìn.

Is e an rud a tha inntinneach gu bheil SCSU a’ cleachdadh bheachdan a tha glè choltach ris an fheadhainn a thàinig mi suas leam fhìn (an àite a’ bhun-bheachd air “aibideil” bidh iad a’ cleachdadh “uinneagan”, agus tha barrachd dhiubh rim faighinn na th’ agam). Aig an aon àm, tha eas-bhuannachdan aig a 'chruth seo cuideachd: tha e beagan nas fhaisge air algorithms teannachaidh na feadhainn còdachadh. Gu sònraichte, tha an inbhe a ’toirt seachad mòran dhòighean riochdachaidh, ach chan eil e ag ràdh mar a roghnaicheas tu am fear as fheàrr - airson seo, feumaidh an encoder seòrsa de heuristics a chleachdadh. Mar sin, bidh encoder SCSU a bheir a-mach pacadh math nas iom-fhillte agus nas duilghe na an algairim agam.

Airson coimeas a dhèanamh, ghluais mi buileachadh an ìre mhath sìmplidh de SCSU gu JavaScript - a thaobh meud còd bha e coltach ris an UTF-C agam, ach ann an cuid de chùisean bha an toradh deichean sa cheud nas miosa (uaireannan dh’ fhaodadh e a dhol thairis air, ach chan ann le mòran). Mar eisimpleir, chaidh teacsaichean ann an Eabhra agus Greugais a chòdachadh le UTF-C 60% nas fheàrr na SCSU (is dòcha mar thoradh air na h-aibideil teann aca).

Air leth, cuiridh mi ris, a bharrachd air SCSU, gu bheil dòigh eile ann cuideachd airson Unicode a riochdachadh gu dlùth - BOCU-1, ach tha e ag amas air co-chòrdalachd MIME (rud nach robh a dhìth orm) agus a’ gabhail dòigh-obrach beagan eadar-dhealaichte airson còdachadh. Chan eil mi air measadh a dhèanamh air a èifeachdas, ach tha e coltach riumsa nach eil e coltach gum bi e nas àirde na SCSU.

Leasachaidhean a dh’ fhaodadh a bhith ann

Chan eil an algairim a thaisbean mi uile-choitcheann a thaobh dealbhadh (is dòcha gur ann an seo a tha na h-amasan agam a’ dealachadh as motha bho amasan Co-bhanntachd Unicode). Tha mi air iomradh a thoirt mu thràth gun deach a leasachadh gu sònraichte airson aon ghnìomh (a’ stòradh faclair ioma-chànanach ann an craobh ro-leasachan), agus is dòcha nach bi cuid de na feartan aige gu math freagarrach airson gnìomhan eile. Ach faodaidh an fhìrinn nach e inbhe a th’ ann a bhith na bhuannachd - faodaidh tu atharrachadh gu furasta gus freagairt air na feumalachdan agad.

Mar eisimpleir, anns an dòigh fhollaiseach gheibh thu cuidhteas de làthaireachd stàite, dèan còdadh gun stàit - dìreach na ùraich caochladairean offs, auxOffs и is21Bit anns an encoder agus decoder. Anns a 'chùis seo, cha bhith e comasach sreathan de charactaran den aon aibidil a phacadh gu h-èifeachdach, ach bidh gealltanas ann gum bi an aon charactar an-còmhnaidh air a chòdachadh leis na h-aon bytes, ge bith dè an co-theacsa.

A bharrachd air an sin, faodaidh tu an encoder a dhèanamh freagarrach do chànan sònraichte le bhith ag atharrachadh an stàit bunaiteach - mar eisimpleir, le fòcas air teacsaichean Ruiseanach, suidhich an encoder agus an decoder aig an toiseach offs = 0x0400 и auxOffs = 0. Tha seo gu sònraichte a’ dèanamh ciall a thaobh modh gun stàit. San fharsaingeachd, bidh seo coltach ri bhith a’ cleachdadh an t-seann chòdachadh ochd-pìosan, ach gun a bhith a’ toirt air falbh comas caractaran a chuir a-steach às a h-uile Unicode mar a dh’ fheumar.

Is e ana-cothrom eile a chaidh ainmeachadh roimhe seo, ann an teacsa mòr air a chòdachadh ann an UTF-C, nach eil dòigh luath air crìoch a’ charactar a lorg as fhaisge air byte neo-riaghailteach. Ma ghearras tu dheth an tè mu dheireadh, can, 100 bytes bhon bhufair a chaidh a chòdachadh, tha cunnart ann gum faigh thu sgudal leis nach urrainn dhut dad a dhèanamh leis. Chan eil an còdachadh air a dhealbhadh airson logaichean ioma-gigabyte a stòradh, ach san fharsaingeachd faodar seo a cheartachadh. Beit 0xBF cha bu chòir dha a bhith a’ nochdadh mar a’ chiad byte (ach dh’ fhaodadh gur e an dàrna no an treas fear). Mar sin, nuair a bhios tu a’ còdachadh, faodaidh tu an t-sreath a chuir a-steach 0xBF 0xBF 0xBF a h-uile, can, 10 KB - an uairsin, ma dh'fheumas tu crìoch a lorg, bidh e gu leòr airson a 'phìos taghte a sganadh gus an lorgar comharraiche coltach ris. A 'leantainn air an fhear mu dheireadh 0xBF tha e cinnteach gur e toiseach caractar. (Nuair a thèid a chòdachadh, feumar an sreath seo de thrì bytes, gu dearbh, a leigeil seachad.)

A 'togail suas

Ma tha thu air leughadh cho fada seo, meala-naidheachd air! Tha mi an dòchas gun do dh’ ionnsaich thu, mar mise, rudeigin ùr (no gun do dh’ ùraich thu do chuimhne) mu structar Unicode.

Baidhsagal eile: bidh sinn a’ stòradh sreangan Unicode 30-60% nas toinnte na UTF-8
Duilleag demo. Tha eisimpleir Eabhra a 'sealltainn na buannachdan thairis air an dà chuid UTF-8 agus SCSU.

Cha bu chòir beachdachadh air an rannsachadh a tha air a mhìneachadh gu h-àrd mar bhriseadh air inbhean. Ach, sa chumantas tha mi riaraichte le toraidhean na h-obrach agam, agus mar sin tha mi toilichte leotha roinn: mar eisimpleir, chan eil ach 1710 bytes ann an leabharlann JS air a lughdachadh (agus chan eil eisimeileachd ann, gu dearbh). Mar a thuirt mi gu h-àrd, gheibhear an obair aice aig duilleag demo (tha seata de theacsaichean ann cuideachd air an urrainnear a choimeas ri UTF-8 agus SCSU).

Mu dheireadh, tarraingidh mi aire a-rithist gu cùisean anns a bheil UTF-C air a chleachdadh chan eil luach air:

  • Ma tha na loidhnichean agad fada gu leòr (bho 100-200 caractar). Anns a 'chùis seo, bu chòir dhut smaoineachadh mu bhith a' cleachdadh algorithms teannachaidh mar deflate.
  • Ma tha feum agad air follaiseachd ASCII, is e sin, tha e cudromach dhut nach eil còdan ASCII anns na sreathan còdaichte nach robh san t-sreath thùsail. Faodar an fheum air seo a sheachnadh ma bhios tu, nuair a bhios tu ag eadar-obrachadh le APIan treas-phàrtaidh (mar eisimpleir, ag obair le stòr-dàta), a’ dol seachad air an toradh còdaidh mar sheata eas-chruthach de bytes, agus chan ann mar shreathan. Rud eile, tha cunnart ann gum faigh thu so-leòntachd ris nach robh dùil.
  • Ma tha thu airson a bhith comasach air crìochan caractar a lorg gu sgiobalta aig casg neo-riaghailteach (mar eisimpleir, nuair a thèid pàirt de loidhne a mhilleadh). Faodar seo a dhèanamh, ach dìreach le bhith a 'sganadh an loidhne bhon toiseach (no a' cleachdadh an atharrachaidh a chaidh a mhìneachadh san earrann roimhe).
  • Ma dh’ fheumas tu gnìomhachd a dhèanamh gu sgiobalta air susbaint nan teudan (rèitich iad, lorg fo-thalamh annta, concatenate). Feumaidh seo sreangan a dhì-chòdachadh an toiseach, agus mar sin bidh UTF-C nas slaodaiche na UTF-8 anns na cùisean sin (ach nas luaithe na algorithms teannachaidh). Leis gu bheil an aon sreang an-còmhnaidh air a chòdachadh san aon dòigh, chan eil feum air coimeas ceart de chòdachadh agus faodar a dhèanamh air stèidh byte-by-byte.

update: an neach-cleachdaidh Tyomitch anns na beachdan gu h-ìosal air graf a phostadh a’ soilleireachadh crìochan iomchaidheachd UTF-C. Tha e a’ sealltainn gu bheil UTF-C nas èifeachdaiche na algairim teannachaidh adhbhar coitcheann (caochladh air LZW) fhad ‘s a tha an t-sreang pacaichte nas giorra ~140 caractar (ge-tà, tha mi a 'toirt fa-near gun deach an coimeas a dhèanamh air aon teacsa; airson cànanan eile faodaidh an toradh a bhith eadar-dhealaichte).
Baidhsagal eile: bidh sinn a’ stòradh sreangan Unicode 30-60% nas toinnte na UTF-8

Source: www.habr.com

Cuir beachd ann