{"id":95911,"date":"2020-10-05T01:42:09","date_gmt":"2020-10-04T23:42:09","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/eshhyo-odin-velosiped-hranim-yunikodnye-stroki-na-30-60-kompaktnee-chem-utf-8"},"modified":"2020-10-05T01:42:09","modified_gmt":"2020-10-04T23:42:09","slug":"eshhyo-odin-velosiped-hranim-yunikodnye-stroki-na-30-60-kompaktnee-chem-utf-8","status":"publish","type":"post","link":"https:\/\/prohoster.info\/sk\/blog\/administrirovanie\/eshhyo-odin-velosiped-hranim-yunikodnye-stroki-na-30-60-kompaktnee-chem-utf-8","title":{"rendered":"E\u0161te jeden bicykel: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"E\u0161te jeden bicykel: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8\" src=\"\/wp-content\/uploads\/2020\/10\/56c10bad377127b711bdb204ee300772.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAk ste v\u00fdvoj\u00e1r a pred vami je \u00faloha vybra\u0165 k\u00f3dovanie, skoro v\u017edy bude spr\u00e1vnym rie\u0161en\u00edm Unicode. Konkr\u00e9tny sp\u00f4sob reprezent\u00e1cie z\u00e1vis\u00ed od kontextu, ale \u010dasto tu je tie\u017e univerz\u00e1lna odpove\u010f \u2014 UTF-8. Je dobr\u00e9, preto\u017ee umo\u017e\u0148uje pou\u017e\u00edva\u0165 v\u0161etky znaky Unicode, bez plytvania <em>pr\u00edli\u0161<\/em> ve\u013ea bajtov vo v\u00e4\u010d\u0161ine pr\u00edpadov. Pravda, pre jazyky pou\u017e\u00edvaj\u00face nielen latinku, \"nie pr\u00edli\u0161 ve\u013ea\" \u2014 to je aspo\u0148 <strong>dva bajty na znak<\/strong>. Je mo\u017en\u00e9 lep\u0161ie, bez n\u00e1vratu k pravek\u00fdm k\u00f3dovaniam, ktor\u00e9 n\u00e1s obmedzuj\u00fa na len 256 dostupn\u00fdch znakov?<\/p>\n<p>Ni\u017e\u0161ie navrhujem obozn\u00e1mi\u0165 sa s moj\u00edm pokusom odpoveda\u0165 na t\u00fato ot\u00e1zku a implement\u00e1ciu relat\u00edvne jednoduch\u00e9ho algoritmu, ktor\u00fd umo\u017e\u0148uje uklada\u0165 re\u0165azce v drvivej v\u00e4\u010d\u0161ine jazykov sveta, bez prid\u00e1vania tej nadbyto\u010dnosti, ktor\u00e1 je v UTF-8.<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p><i>Disklejmer.<\/i> I hne\u010f urob\u00edm nieko\u013eko d\u00f4le\u017eit\u00fdch vyjadren\u00ed: <strong>op\u00edsan\u00e9 rie\u0161enie sa nepon\u00faka ako univerz\u00e1lna n\u00e1hrada za UTF-8<\/strong>, je vhodn\u00e9 len v \u00fazkom zozname pr\u00edpadov (o ktor\u00fdch budem nesk\u00f4r) a ur\u010dite ho nemo\u017eno pou\u017e\u00edva\u0165 na interakciu s extern\u00fdmi API (ktor\u00e9 o \u0148om ani nevedia). Naj\u010dastej\u0161ie pre kompaktne \u00falo\u017eisko ve\u013ek\u00fdch objemov textov\u00fdch \u00fadajov sa hodia algoritmy v\u0161eobecn\u00e9ho kompresie (napr\u00edklad deflate). Navy\u0161e, u\u017e po\u010das vytv\u00e1rania svojho rie\u0161enia som na\u0161iel existuj\u00faci \u0161tandard v samotnom Unicode, ktor\u00fd rie\u0161i t\u00fa ist\u00fa \u00falohu \u2014 je o nie\u010do zlo\u017eitej\u0161\u00ed (a \u010dasto hor\u0161\u00ed), ale predsa len je to prijat\u00fd \u0161tandard, nie nie\u010do zostaven\u00e9 na kolene. O \u0148om tie\u017e hovor\u00edm.<\/p>\n<h2>O Unicode a UTF-8<\/h2>\n<p>\nNa za\u010diatok \u2014 p\u00e1r slov o tom, \u010do vlastne je <strong>Unicode<\/strong> a <strong>UTF-8<\/strong>.<\/p>\n<p>Ako vieme, predt\u00fdm boli popul\u00e1rne 8-bitov\u00e9 k\u00f3dovania. S nimi to bolo jednoduch\u00e9: 256 znakov sa d\u00e1 o\u010d\u00edslova\u0165 \u010d\u00edslami od 0 do 255, a \u010d\u00edsla od 0 do 255 s\u00fa samozrejme reprezentovate\u013en\u00e9 v podobe jedn\u00e9ho bajtu. Ak sa vr\u00e1time na \u00fapln\u00fd za\u010diatok, k\u00f3dovanie ASCII je obmedzen\u00e9 len na 7 bitov, preto najstar\u0161\u00ed bit v jeho bajtovom zast\u00fapen\u00ed je nulov\u00fd, a v\u00e4\u010d\u0161ina 8-bitov\u00fdch k\u00f3dovan\u00ed je s n\u00edm kompatibiln\u00e1 (li\u0161ia sa len v \"hornej\" \u010dasti, kde najstar\u0161\u00ed bit je jeden).<\/p>\n<p>\u010c\u00edm sa k\u00f3dovanie l\u00ed\u0161i od Unicode a pre\u010do s\u00fa s n\u00edm spojen\u00e9 r\u00f4zne reprezent\u00e1cie \u2013 UTF-8, UTF-16 (BE a LE), UTF-32? Pozrime sa na to postupne.<\/p>\n<p>Hlavn\u00fd \u0161tandard Unicode popisuje iba zodpovednosti medzi znakmi (a v niektor\u00fdch pr\u00edpadoch \u2013 jednotliv\u00fdmi komponentami znakov) a ich \u010d\u00edslami. Mo\u017en\u00fdch \u010d\u00edsel v tomto \u0161tandarde je ve\u013emi ve\u013ea \u2013 od <code><b>0x00<\/b><\/code> do <code><b>0x10FFFF<\/b><\/code> (1 114 112 kusov). Keby sme chceli ulo\u017ei\u0165 \u010d\u00edslo v takom rozsahu do premennej, ani 1, ani 2 bajty by n\u00e1m nesta\u010dili. A preto\u017ee na\u0161e procesory nie s\u00fa optimalizovan\u00e9 na pr\u00e1cu s trojbajtov\u00fdmi \u010d\u00edslami, museli by sme na jeden znak pou\u017e\u00edva\u0165 cel\u00e9 4 bajty! To je UTF-32, ale pr\u00e1ve kv\u00f4li tejto \"plytvan\u00ed\" tento form\u00e1t nie je popul\u00e1rny.<\/p>\n<p>Na\u0161\u0165astie s\u00fa znaky v Unicode usporiadan\u00e9 nie n\u00e1hodne. Ich ve\u013ek\u00e9 mno\u017estvo je rozdelen\u00e9 na 17 \u201e<em>rov\u00edn<\/em>\", z ktor\u00fdch ka\u017ed\u00e1 obsahuje 65536 (<code><b>0x10000<\/b><\/code>) \u00ab<em>k\u00f3dov\u00fdch bodov<\/em>\"). Pojem \u201ek\u00f3dov\u00fd bod\u201c tu znamen\u00e1 jednoducho <em>\u010d\u00edslo znaku<\/em>, ktor\u00e9 mu priradil Unicode. Ako u\u017e bolo povedan\u00e9, v Unicode s\u00fa \u010d\u00edslovan\u00e9 nielen jednotliv\u00e9 znaky, ale aj ich komponenty a pomocn\u00e9 ozna\u010denia (a niekedy ani nie s\u00fa priraden\u00e9 \u010d\u00edslu \u2013 mo\u017eno do\u010dasne, ale pre n\u00e1s to nie je a\u017e tak\u00e9 d\u00f4le\u017eit\u00e9), preto je presnej\u0161ie v\u017edy hovori\u0165 o po\u010dte \u010d\u00edsel ako o ich znakoch. Napriek tomu v \u010fal\u0161om texte budem \u010dastej\u0161ie pou\u017e\u00edva\u0165 slovo \u201eznak\u201c, pri\u010dom mysl\u00edm na term\u00edn \u201ek\u00f3dov\u00fd bod\u201c.<\/p>\n<p><img decoding=\"async\" alt=\"E\u0161te jeden bicykel: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8\" src=\"\/wp-content\/uploads\/2020\/10\/7ad84b571a8025582fdbc3db956cb3b0.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Roviny Unicode. Ako vidno, v\u00e4\u010d\u0161ina (roviny od 4 po 13) je st\u00e1le nevyu\u017eit\u00e1.<\/i><\/p>\n<p>Najzauj\u00edmavej\u0161ie je, \u017ee cel\u00e1 z\u00e1kladn\u00e1 \"m\u00e4so\" le\u017e\u00ed v nulovej rovine, naz\u00fdva sa \"<em>Basic Multilingual Plane<\/em>\". Ak riadok obsahuje text v jednom z modern\u00fdch jazykov (vr\u00e1tane \u010d\u00edn\u0161tiny), za t\u00fato rovinu sa nedostanete. Ale ani nem\u00f4\u017eete odstr\u00e1ni\u0165 zvy\u0161ok Unicode \u2014 napr\u00edklad emoji sa v\u00e4\u010d\u0161inou nach\u00e1dzaj\u00fa na konci nasleduj\u00facej roviny, \"<em>Supplementary Multilingual Plane<\/em>\" (t\u00e1 sa rozprestiera od <code><b>0x10000<\/b><\/code> do <code><b>0x1FFFF<\/b><\/code>). Preto UTF-16 pristupuje takto: v\u0161etky znaky, ktor\u00e9 spadaj\u00fa do <em>Basic Multilingual Plane<\/em>, k\u00f3duj\u00fa sa \u201eako s\u00fa\u201c, zodpovedaj\u00facim im dvojbajtov\u00fdm \u010d\u00edslom. Av\u0161ak \u010das\u0165 \u010d\u00edsel v tomto rozsahu v\u00f4bec neozna\u010duje konkr\u00e9tne symboly, ale nazna\u010duje, \u017ee za touto dvojicou bajtov je potrebn\u00e9 zv\u00e1\u017ei\u0165 e\u0161te jednu \u2013 skombinovan\u00edm hodn\u00f4t t\u00fdchto \u0161tyroch bajtov spolu dostaneme \u010d\u00edslo, ktor\u00e9 pokr\u00fdva cel\u00fd povolen\u00fd rozsah Unicode. Tak\u00e9to zobrazenie sa naz\u00fdva \u201esurrog\u00e1tne p\u00e1ry\u201c \u2013 mo\u017eno ste o nich po\u010duli.<\/p>\n<p>Tak\u017ee, UTF-16 vy\u017eaduje dva alebo (v ve\u013emi zriedkav\u00fdch pr\u00edpadoch) \u0161tyri bajty na jeden \u201ek\u00f3dov\u00fd bod\u201c. Je to lep\u0161ie ako neust\u00e1le pou\u017e\u00edva\u0165 \u0161tyri bajty, ale latinka (a in\u00e9 ASCII symboly) pri takomto k\u00f3dovan\u00ed spotreb\u00fava polovicu obsaden\u00e9ho miesta na nuly. UTF-8 m\u00e1 za cie\u013e to opravi\u0165: ASCII v \u0148om zaber\u00e1, ako predt\u00fdm, iba jeden bajt; k\u00f3dy od <code><b>0x80<\/b><\/code> do <code><b>0x7FF<\/b><\/code> \u2014 dvoch bajtov; od <code><b>0x800<\/b><\/code> do <code><b>0xFFFF<\/b><\/code> \u2014 troch, a od <code><b>0x10000<\/b><\/code> do <code><b>0x10FFFF<\/b><\/code> \u2014 \u0161tyroch. Z jednej strany, latinke sa to vyplatilo: vr\u00e1tila sa kompatibilita s ASCII a aj rozdelenie je viac rovnomerne \u201erozmazan\u00e9\u201c od 1 do 4 bajtov. Ale abecedy, in\u00e9 ako latinsk\u00e1, bohu\u017eia\u013e, nijako nevyhr\u00e1vaj\u00fa v porovnan\u00ed s UTF-16, a mnoh\u00e9 teraz vy\u017eaduj\u00fa tri bajty namiesto dvoch \u2013 rozsah pokryt\u00fd dvojbajtov\u00fdm z\u00e1pisom sa z\u00fa\u017eil 32-kr\u00e1t, s <code><b>0xFFFF<\/b><\/code> do <code><b>0x7FF<\/b><\/code>, a do nej u\u017e nepatr\u00ed ani \u010d\u00ednsky, ani napr\u00edklad gruz\u00ednsky. Cyrilika a e\u0161te p\u00e4\u0165 abecied \u2014 hur\u00e1 \u2014 mali \u0161\u0165astie, 2 bajty na symbol.<\/p>\n<p>Pre\u010do to takto vych\u00e1dza? Po\u010fme sa pozrie\u0165, ako UTF-8 predstavuje k\u00f3dy symbolov:<br \/>\n<img decoding=\"async\" alt=\"E\u0161te jeden bicykel: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8\" src=\"\/wp-content\/uploads\/2020\/10\/4ef4fe9e949cd75295c45c053dbca6d3.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nPriamo na zobrazenie \u010d\u00edsel sa tu pou\u017eili bity, ozna\u010den\u00e9 symbolom <code><b>x<\/b><\/code>. Je vidno, \u017ee v dvojbajtovom z\u00e1pise je tak\u00fdch bitov iba 11 (z 16). Veden\u00e9 bity tu nes\u00fa len slu\u017eobn\u00fa funkciu. V pr\u00edpade \u0161tyrbajtov\u00e9ho z\u00e1pisu a \u00faplne pod \u010d\u00edslo k\u00f3dov\u00e9ho bodu je vy\u010dlenen\u00fdch 21 bit z 32 \u2013 zdalo by sa, \u017ee tu by sta\u010dili aj tri bajty (ktor\u00e9 d\u00e1vaj\u00fa spolu 24 bitov), ale slu\u017eobn\u00e9 markery zjedia pr\u00edli\u0161 ve\u013ea.<\/p>\n<p>Je to zl\u00e9? V skuto\u010dnosti nie ve\u013emi. Na jednej strane, ak ve\u013emi db\u00e1me na obsadzovan\u00e9 miesto, m\u00e1me algoritmy kompresie, ktor\u00e9 \u013eahko odstr\u00e1nia v\u0161etku nadbyto\u010dn\u00fa entropiu a redundanciu. Na druhej strane, cie\u013eom Unicode bolo poskytn\u00fa\u0165 maxim\u00e1lne univerz\u00e1lne k\u00f3dovanie. Napr\u00edklad re\u0165azec zak\u00f3dovan\u00fd v UTF-8 m\u00f4\u017eeme zveri\u0165 k\u00f3du, ktor\u00fd predt\u00fdm pracoval iba s ASCII, a neboj\u00edme sa, \u017ee tam uvid\u00ed znak z ASCII rozsahu, ktor\u00fd tam naozaj nie je (ve\u010f v UTF-8 v\u0161etky bajty za\u010d\u00ednaj\u00face s nulov\u00fdm bitom s\u00fa pr\u00e1ve ASCII). A ak sa rozhodneme n\u00e1hodou odstr\u00e1ni\u0165 mal\u00fd koniec z ve\u013ek\u00e9ho re\u0165azca, bez dekomprimovania na za\u010diatku (alebo obnovi\u0165 \u010das\u0165 inform\u00e1ci\u00ed po po\u0161kodenom \u00faseku) \u2014 nie je pre n\u00e1s \u0165a\u017ek\u00e9 n\u00e1js\u0165 to posunutie, kde za\u010d\u00edna nejak\u00fd znak (sta\u010d\u00ed presko\u010di\u0165 bajty, ktor\u00e9 maj\u00fa bitov\u00fd prefix. <code><b>10<\/b><\/code>).<\/p>\n<h2>Pre\u010do teda vym\u00fd\u0161\u013ea\u0165 nie\u010do nov\u00e9?<\/h2>\n<p>\nZ\u00e1rove\u0148 sa ob\u010das vyskytn\u00fa situ\u00e1cie, ke\u010f s\u00fa algoritmy kompresie ako deflate zle aplikovate\u013en\u00e9 a chceme dosiahnu\u0165 kompaktn\u00e9 ukladanie re\u0165azcov. Osobne som sa s takouto \u00falohou stretol, ke\u010f som uva\u017eoval o kon\u0161trukcii <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Radix_tree\">komprimovan\u00e9ho prefixov\u00e9ho stromu<\/a><\/noindex> pre ve\u013ek\u00fd slovn\u00edk, ktor\u00fd zah\u0155\u0148a slov\u00e1 v r\u00f4znych jazykoch. Na jednej strane \u2014 ka\u017ed\u00e9 slovo je ve\u013emi kr\u00e1tke, preto bude jeho kompresia neefekt\u00edvna. Na druhej strane \u2014 implement\u00e1cia stromu, ktor\u00fa som zva\u017eoval, bola navrhnut\u00e1 tak, aby ka\u017ed\u00fd bajt ukladan\u00e9ho re\u0165azca vytv\u00e1ral samostatn\u00fd vrchol stromu, tak\u017ee minimaliz\u00e1cia ich mno\u017estva bola ve\u013emi u\u017eito\u010dn\u00e1. V mojej kni\u017enici <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/deNULL\/Az.js\">Az.js<\/a><\/noindex> (rovnako ako v <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/kmike\/pymorphy2\">pymorphy2<\/a><\/noindex>, na ktorom je zalo\u017een\u00e1) sa podobn\u00fd probl\u00e9m rie\u0161i jednoducho \u2014 re\u0165azce, ktor\u00e9 s\u00fa zabalen\u00e9 do <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Deterministic_acyclic_finite_state_automaton\">DAWG<\/a><\/noindex>-slovn\u00edka, sa tam ukladaj\u00fa v <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/deNULL\/Az.js\/blob\/master\/src\/az.dawg.js\">starom dobrom CP1251.<\/a><\/noindex>Ale, ako nie je \u0165a\u017ek\u00e9 pochopi\u0165, to dobre funguje len pre obmedzen\u00fa abecedu \u2014 re\u0165azec v \u010d\u00edn\u0161tine do tak\u00e9ho slovn\u00edka u\u017e nenasklad\u00e1te.<\/p>\n<p>Osobitne zd\u00f4razn\u00edm e\u0161te jednu nepr\u00edjemn\u00fa nuansu, ktor\u00e1 vznik\u00e1 pri pou\u017eit\u00ed UTF-8 v takej d\u00e1tovej \u0161trukt\u00fare. Na obr\u00e1zku vy\u0161\u0161ie je vidie\u0165, \u017ee pri z\u00e1pise znaku vo forme dvoch bajtov sa bity t\u00fdkaj\u00face sa jeho \u010d\u00edsla nezhoduj\u00fa, ale s\u00fa preru\u0161en\u00e9 p\u00e1r bit <code><b>10<\/b><\/code> uprostred: <code><b>110xxxxx 10xxxxxx<\/b><\/code>. Kv\u00f4li tomu, ke\u010f v k\u00f3de znaku prete\u010d\u00fa ni\u017e\u0161ie 6 bity druh\u00e9ho bajtu (t.j. d\u00f4jde k prechodu <code><b>10111111<\/b><\/code> \u2192 <code><b>10000000<\/b><\/code>), men\u00ed sa aj prv\u00fd bajt. Ukazuje sa, \u017ee p\u00edsmeno \u201ep\u201c je ozna\u010dovan\u00e9 bajtmi <code><b>0xD0 0xBF<\/b><\/code>, a nasleduj\u00faca p\u00edsmeno \u201er\u201c \u2014 u\u017e <code><b>0xD1 0x80<\/b><\/code>. V prefixovom strome to vedie k rozdeleniu rodi\u010dovsk\u00e9ho uzla na dva \u2014 jeden pre prefix <code><b>0xD0<\/b><\/code>, a druh\u00fd pre <code><b>0xD1<\/b><\/code> (hoci cel\u00e1 cyrilika by mohla by\u0165 k\u00f3dovan\u00e1 iba druh\u00fdm bajtom).<\/p>\n<h2>\u010co som z\u00edskal<\/h2>\n<p>\nKe\u010f som \u010delil tejto \u00falohe, rozhodol som sa precvi\u010di\u0165 si hry s bitmi a z\u00e1rove\u0148 sa lep\u0161ie obozn\u00e1mi\u0165 so \u0161trukt\u00farou Unicode ako celku. V\u00fdsledkom bol form\u00e1t k\u00f3dovania UTF-C (\u201eC\u201c od <em>compact<\/em>), ktor\u00fd spotrebuje maxim\u00e1lne 3 bajty na jeden k\u00f3dov\u00fd bod, a ve\u013emi \u010dasto umo\u017e\u0148uje min\u00fa\u0165 len <strong>jeden \u010fal\u0161\u00ed bajt na cel\u00fd k\u00f3dovan\u00fd riadok<\/strong>. To vedie k tomu, \u017ee na mnoh\u00fdch ne-ASCII abeced\u00e1ch sa tak\u00e9to k\u00f3dovanie ukazuje <strong>o 30-60 % kompaktnej\u0161ie ako UTF-8<\/strong>.<\/p>\n<p>Zostavil som pr\u00edklady implement\u00e1cie algoritmov k\u00f3dovania a dek\u00f3dovania vo forme <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/deNULL\/utf-c\">kni\u017en\u00edc v JavaScripte a Go<\/a><\/noindex>, m\u00f4\u017eete ich slobodne pou\u017e\u00edva\u0165 vo svojom k\u00f3de. Ale predsa len zd\u00f4razn\u00edm, \u017ee v ur\u010ditom zmysle tento form\u00e1t zost\u00e1va \u201ebicyklom\u201c, a neodpor\u00fa\u010dam ho pou\u017e\u00edva\u0165 <strong>bez vedomosti, na \u010do ho potrebujete<\/strong>. Je to predsa len viac experiment ne\u017e v\u00e1\u017ene \u201evylep\u0161enie UTF-8\u201c. Napriek tomu, k\u00f3d je nap\u00edsan\u00fd \u00fah\u013eadne, stru\u010dne, s ve\u013ek\u00fdm mno\u017estvom koment\u00e1rov a pokryt\u00edm testami.<\/p>\n<p><img decoding=\"async\" alt=\"E\u0161te jeden bicykel: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8\" src=\"\/wp-content\/uploads\/2020\/10\/e31978174449cd7de5d8371aaeb9ab2e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>V\u00fdsledok vykonania testov a porovnanie s UTF-8<\/i><\/p>\n<p>E\u0161te som vytvoril <noindex><a rel=\"nofollow\" href=\"https:\/\/denull.github.io\/utf-c\/\">demo str\u00e1nku<\/a><\/noindex>, kde si m\u00f4\u017eete pos\u00fadi\u0165 pr\u00e1cu algoritmu, a \u010falej podrobnej\u0161ie vysvetl\u00edm jeho princ\u00edpy a proces v\u00fdvoja.<\/p>\n<h2>Odstra\u0148ujeme nadbyto\u010dn\u00e9 bity<\/h2>\n<p>\nZa z\u00e1klad som vzal, samozrejme, UTF-8. Prv\u00e1 a najzjavnej\u0161ia vec, ktor\u00fa mo\u017eno zmeni\u0165 \u2014 zn\u00ed\u017ei\u0165 po\u010det riadiacich bitov v ka\u017edom bajte. Napr\u00edklad, prv\u00fd bajt v UTF-8 v\u017edy za\u010d\u00edna bu\u010f s <code><b>0<\/b><\/code>, alebo s <code><b>11<\/b><\/code> \u2014 a prefix <code><b>10<\/b><\/code> je iba u nasleduj\u00facich bajtov. Nahrad\u00edme prefix <code><b>11<\/b><\/code> na <code><b>1<\/b><\/code>, a u nasleduj\u00facich bajtov \u00faplne odstr\u00e1nime prefixy. \u010co dostaneme?<\/p>\n<p><code><b>0xxxxxxx<\/b><\/code> \u2014 1 bajt <br \/>\n<code><b>10xxxxxx xxxxxxxx<\/b><\/code> \u2014 2 bajty <br \/>\n<code><b>110xxxxx xxxxxxxx xxxxxxxx<\/b><\/code> \u2014 3 bajty<\/p>\n<p>Stop, a kde je \u0161tvobajtov\u00e1 z\u00e1pis? A t\u00e1 u\u017e nie je potrebn\u00e1 \u2014 pri z\u00e1pise tromi bajtmi m\u00e1me teraz k dispoz\u00edcii 21 bitov a to sta\u010d\u00ed na v\u0161etky \u010d\u00edsla do <code><b>0x10FFFF<\/b><\/code>.<\/p>\n<p>\u010co sme tu obetovali? Najd\u00f4le\u017eitej\u0161ie \u2014 zistenie hran\u00edc symbolov z \u013eubovo\u013en\u00e9ho miesta v buffere. Nem\u00f4\u017eeme sa jednoducho uchechn\u00fa\u0165 na \u013eubovo\u013en\u00fd bajt a od neho n\u00e1js\u0165 za\u010diatok nasleduj\u00faceho symbolu. To je obmedzenie n\u00e1\u0161ho form\u00e1tu, ale v praxi sa potreba tak\u00e9hoto zriedka vyskytuje. Zvy\u010dajne sme schopn\u00ed prech\u00e1dza\u0165 bufferom od sam\u00e9ho za\u010diatku (najm\u00e4 pokia\u013e ide o kr\u00e1tke riadky).<\/p>\n<p>Situ\u00e1cia s pokryt\u00edm jazykov 2 bajtmi sa tie\u017e zlep\u0161ila: teraz dvojbajtov\u00fd form\u00e1t poskytuje rozsah 14 bitov, a to k\u00f3dy a\u017e do <code><b>0x3FFF<\/b><\/code>. \u010c\u00ed\u0148anom sa nedar\u00ed (ich hieroglyfy s\u00fa v\u00e4\u010d\u0161inou v rozsahu od <code><b>0x4E00<\/b><\/code> do <code><b>0x9FFF<\/b><\/code>), ale Gr\u00e9kom a mnoh\u00fdm in\u00fdm n\u00e1rodom sa u\u013eah\u010dilo \u2014 ich jazyky sa tie\u017e zmestia do 2 bajtov na symbol.<\/p>\n<h2>Zadajte stav enkod\u00e9ra<\/h2>\n<p>\nTeraz sa zamyslime nad vlastnos\u0165ami samotn\u00fdch riadkov. V slovn\u00edku sa naj\u010dastej\u0161ie nach\u00e1dzaj\u00fa slov\u00e1 nap\u00edsan\u00e9 znakmi jedn\u00e9ho p\u00edsma, a pre mnoh\u00e9 in\u00e9 texty to plat\u00ed tie\u017e. Bolo by dobr\u00e9 ur\u010dit\u00e9 raz uvies\u0165 toto p\u00edsmo a potom u\u017e len uv\u00e1dza\u0165 \u010d\u00edslo p\u00edsmena v \u0148om. Pozrime sa, \u010di n\u00e1m umiestnenie znakov v tabu\u013eke Unicode pom\u00f4\u017ee.<\/p>\n<p>Ako bolo uveden\u00e9 vy\u0161\u0161ie, Unicode je rozdelen\u00e9 na <em>plochy<\/em> po 65536 k\u00f3dov ka\u017ed\u00e1. Ale toto delenie nie je ve\u013emi u\u017eito\u010dn\u00e9 (ako u\u017e bolo povedan\u00e9, v\u00e4\u010d\u0161inou sa nach\u00e1dzame v nulovej ploche). Zauj\u00edmavej\u0161ie je delenie na <em>bloky.<\/em> Tieto rozsahy u\u017e nemaj\u00fa pevn\u00e9 d\u013a\u017eky a nes\u00fa v\u00e4\u010d\u0161\u00ed v\u00fdznam \u2014 zvy\u010dajne ka\u017ed\u00fd sp\u00e1ja znaky jedn\u00e9ho p\u00edsma.<\/p>\n<p><img decoding=\"async\" alt=\"E\u0161te jeden bicykel: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8\" src=\"\/wp-content\/uploads\/2020\/10\/61ea5e859d7e6d9c75e977a3579ff28f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Blok, obsahuj\u00faci znaky beng\u00e1lskeho p\u00edsma. \u017dia\u013e, z historick\u00fdch d\u00f4vodov, je to pr\u00edklad nie ve\u013emi hust\u00e9ho balenia \u2014 96 znakov je chaoticky rozmiestnen\u00fdch po 128 k\u00f3dov\u00fdch bodoch bloku.<\/i><\/p>\n<p>Za\u010diatky blokov a ich ve\u013ekosti s\u00fa v\u017edy n\u00e1sobky 16 \u2014 je to urobene jednoducho pre pohodlie. Okrem toho mnoh\u00e9 bloky za\u010d\u00ednaj\u00fa a kon\u010dia na hodnot\u00e1ch, ktor\u00e9 s\u00fa n\u00e1sobkom 128 alebo dokonca 256 \u2014 napr\u00edklad z\u00e1kladn\u00e1 cyrilika zaber\u00e1 256 bajtov od <code><b>0x0400<\/b><\/code> do <code><b>0x04FF<\/b><\/code>. To je celkom pohodln\u00e9: ak raz ulo\u017e\u00edme prefix <code><b>0x04<\/b><\/code>, potom m\u00f4\u017ee by\u0165 ak\u00fdko\u013evek cyrilsk\u00fd znak zap\u00edsan\u00fd jedn\u00fdm bajtom. Pravda, takto strat\u00edme mo\u017enos\u0165 vr\u00e1ti\u0165 sa k ASCII (a k ak\u00fdmko\u013evek in\u00fdm znakom v\u00f4bec). Preto to rob\u00edme takto:<\/p>\n<ol>\n<li>Dva bajty <code><b>10yyyyyy yxxxxxxx<\/b><\/code> nie len ozna\u010duj\u00fa znak s \u010d\u00edslom <code><b>yyyyyy yxxxxxxx<\/b><\/code>, ale aj menia <em>aktu\u00e1lne p\u00edsmo<\/em> na <code><b>yyyyyy y0000000<\/b><\/code> t.j. zapam\u00e4t\u00e1me si v\u0161etky bity okrem najni\u017e\u0161\u00edch <strong>7 bit<\/strong>);<\/li>\n<li>Jeden bajt <code><b>0xxxxxxx<\/b><\/code> je symbol aktu\u00e1lneho p\u00edsma. Je potrebn\u00e9 ho jednoducho s\u010d\u00edta\u0165 s posunom, ktor\u00fd sme si zapam\u00e4tali v kroku 1. K\u00fdm sme p\u00edsmo nemenili, posun je rovn\u00fd nule, a preto sme si zachovali kompatibilitu s ASCII.<\/li>\n<\/ol>\n<p>\nPodobne pre k\u00f3dy, ktor\u00e9 vy\u017eaduj\u00fa 3 bajty:<\/p>\n<ol>\n<li>Tri bajty <code><b>110yyyyy yxxxxxxx xxxxxxxx<\/b><\/code> ozna\u010duj\u00fa znak s \u010d\u00edslom <code><b>yyyyyy yxxxxxxx xxxxxxxx<\/b><\/code>, menia <em>aktu\u00e1lne p\u00edsmo<\/em> na <code><b>yyyyyy y0000000 00000000<\/b><\/code> (zapam\u00e4tali sme si v\u0161etko, okrem najni\u017e\u0161\u00edch <strong>15 bit<\/strong>), a nastavuj\u00fa pr\u00edznak, \u017ee teraz sme v <em>dlh\u00fdch<\/em> v re\u017eime (pri zmene p\u00edsma sp\u00e4\u0165 na dvojbytov\u00fd tento pr\u00edznak resetujeme);<\/li>\n<li>Dva bajty <code><b>0xxxxxxx xxxxxxxx<\/b><\/code> v dlhom re\u017eime je to symbol aktu\u00e1lneho p\u00edsma. Podobne, sklada\u0165 ho budeme so posunom z kroku 1. Cel\u00fd rozdiel je len v tom, \u017ee teraz \u010d\u00edtame po dva bajty (preto\u017ee sme pre\u0161li do tak\u00e9ho re\u017eimu).<\/li>\n<\/ol>\n<p>\nZnie to dobre: teraz, k\u00fdm mus\u00edme k\u00f3dova\u0165 znaky z toho ist\u00e9ho 7-bitov\u00e9ho rozsahu Unicode, m\u00ed\u0148ame 1 zbyto\u010dn\u00fd bajt na za\u010diatku a iba po bajte na ka\u017ed\u00fd znak.<\/p>\n<p><img decoding=\"async\" alt=\"E\u0161te jeden bicykel: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8\" src=\"\/wp-content\/uploads\/2020\/10\/084d636a25dccdaa9f5a6eb5233c8e99.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Pr\u00e1ca jednej z ran\u00fdch verzi\u00ed. U\u017e \u010dasto obch\u00e1dza UTF-8, ale st\u00e1le je \u010do zlep\u0161ova\u0165.<\/i><\/p>\n<p>\u010co sa zhor\u0161ilo? Po prv\u00e9, m\u00e1me zaveden\u00fd stav, a to konkr\u00e9tne <em>posun aktu\u00e1lneho p\u00edsma<\/em> a pr\u00edznak <em>dlh\u00e9ho re\u017eimu<\/em>. To n\u00e1s navy\u0161e obmedzuje: teraz m\u00f4\u017eu by\u0165 rovnak\u00e9 znaky k\u00f3dovan\u00e9 r\u00f4znymi sp\u00f4sobmi v r\u00f4znych kontextoch. H\u013eadanie podre\u0165azcov, napr\u00edklad, bude potrebn\u00e9 vykon\u00e1va\u0165 u\u017e s oh\u013eadom na toto, a nie len porovn\u00e1van\u00edm bajtov. Po druh\u00e9, akon\u00e1hle sme zmenili p\u00edsmo, zle je to s k\u00f3dovan\u00edm ASCII znakov (a to nie je len latinka, ale aj z\u00e1kladn\u00e1 interpunkcia vr\u00e1tane medzier) \u2014 vy\u017eaduj\u00fa op\u00e4tovn\u00fa zmenu p\u00edsma na 0, teda zase zbyto\u010dn\u00fd bajt (a potom e\u0161te \u010fal\u0161\u00ed, aby sme sa vr\u00e1tili k n\u00e1\u0161mu hlavn\u00e9mu).<\/p>\n<h2>Jedno p\u00edsmo je dobr\u00e9, dve s\u00fa lep\u0161ie<\/h2>\n<p>\nSk\u00fasime trochu zmeni\u0165 na\u0161e bitov\u00e9 prefixy, vtesnene k trom vy\u0161\u0161ie pop\u00edsan\u00fdm e\u0161te jeden:<\/p>\n<p><code><b>0xxxxxxx<\/b><\/code> \u2014 1 bajt v be\u017enom re\u017eime, 2 v dlhom <br \/>\n<code><b>11xxxxxx<\/b><\/code> \u2014 1 bajt <br \/>\n<code><b>100xxxxx xxxxxxxx<\/b><\/code> \u2014 2 bajty <br \/>\n<code><b>101xxxxx xxxxxxxx xxxxxxxx<\/b><\/code> \u2014 3 bajty<\/p>\n<p><img decoding=\"async\" alt=\"E\u0161te jeden bicykel: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8\" src=\"\/wp-content\/uploads\/2020\/10\/fa1eca1adb80b15a4cf4f60f57a09c6c.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nTeraz v dvojbajtovom z\u00e1pise je na jeden dostupn\u00fd bit menej \u2014 zmestia sa k\u00f3dov\u00e9 body a\u017e do <code><b>0x1FFF<\/b><\/code>, a ne <code><b>0x3FFF<\/b><\/code>. Napriek tomu, st\u00e1le je to pocite\u013ene viac, ne\u017e v dvojbajtov\u00fdch k\u00f3doch UTF-8, v\u00e4\u010d\u0161ina roz\u0161\u00edren\u00fdch jazykov sa st\u00e1le zmest\u00ed, najv\u00fdraznej\u0161ia strata \u2014 vypadla <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%A5%D0%B8%D1%80%D0%B0%D0%B3%D0%B0%D0%BD%D0%B0\">hiraagana<\/a><\/noindex> a <noindex><a rel=\"nofollow\" href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%9A%D0%B0%D1%82%D0%B0%D0%BA%D0%B0%D0%BD%D0%B0\">katakana<\/a><\/noindex>, Japonci s\u00fa smutn\u00ed.<\/p>\n<p>Ak\u00fd je to nov\u00fd k\u00f3d <code><b>11xxxxxx<\/b><\/code>? \u042d\u0442\u043e \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u00ab\u0437\u0430\u0433\u0430\u0448\u043d\u0438\u043a\u00bb \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u043c \u0432 64 \u0441\u0438\u043c\u0432\u043e\u043b\u0430, \u043e\u043d \u0434\u043e\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043d\u0430\u0448 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0430\u043b\u0444\u0430\u0432\u0438\u0442, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u043d\u0430\u0437\u0432\u0430\u043b \u0435\u0433\u043e \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c (<em>auxiliary<\/em>) p\u00edsmom. Ke\u010f prep\u00edname aktu\u00e1lne p\u00edsmo, kus star\u00e9ho p\u00edsma sa st\u00e1va pomocn\u00fdm. Napr\u00edklad, pre\u0161li sme z ASCII na cyriliku \u2014 v \u201ez\u00e1sobe\u201c je teraz 64 znakov, obsahuj\u00facich <strong>latinku, \u010d\u00edslice, medzery a \u010diarku<\/strong> (naj\u010dastej\u0161ie vkladanie v ne-ASCII textoch). Vr\u00e1tili sme sa sp\u00e4\u0165 na ASCII \u2014 a pomocn\u00fdm p\u00edsmom sa stane hlavn\u00e1 \u010das\u0165 cyriliky.<\/p>\n<p>V\u010faka pr\u00edstupu k dvom abeced\u00e1m m\u00f4\u017eeme spracova\u0165 ve\u013ek\u00e9 mno\u017estvo textov s minim\u00e1lnymi n\u00e1kladmi na prep\u00ednanie abeced (interpunkcia sa v\u00e4\u010d\u0161inou vr\u00e1ti sp\u00e4\u0165 do ASCII, ale n\u00e1sledne mnoh\u00e9 ne-ASCII symboly budeme z\u00edskava\u0165 u\u017e z doplnkovej abecedy bez op\u00e4tovn\u00e9ho prep\u00ednania).<\/p>\n<p>Bonus: ozna\u010den\u00edm doplnkovej abecedy predponou <code><b>11xxxxxx<\/b><\/code> a nastaven\u00edm jej po\u010diato\u010dn\u00e9ho posunu na <code><b>0xC0<\/b><\/code>, m\u00e1me \u010diasto\u010dn\u00fa kompatibilitu s CP1252. In\u00fdmi slovami, mnoh\u00e9 (ale nie v\u0161etky) z\u00e1padoeur\u00f3pske texty k\u00f3dovan\u00e9 v CP1252 bud\u00fa vyzera\u0165 rovnako aj v UTF-C.<\/p>\n<p>Tu v\u0161ak nast\u00e1va probl\u00e9m: ako z hlavnej abecedy z\u00edska\u0165 pomocn\u00fa? M\u00f4\u017eeme ponecha\u0165 rovnak\u00e9 posunutie, ale \u2014 \u017eia\u013e \u2014 tu u\u017e \u0161trukt\u00fara Unicode hr\u00e1 proti n\u00e1m. Ve\u013emi \u010dasto hlavn\u00e1 \u010das\u0165 abecedy nie je na za\u010diatku bloku (napr\u00edklad, rusk\u00e9 ve\u013ek\u00e9 \u201e\u0410\u201c m\u00e1 k\u00f3d <code>0x04<b>10<\/b><\/code>, hoci cyrilsk\u00fd blok za\u010d\u00edna s <code>0x04<b>00<\/b><\/code>). T\u00fdmto sp\u00f4sobom, ak zoberieme do \u201erezervy\u201c prv\u00fdch 64 symbolov, m\u00f4\u017eeme strati\u0165 pr\u00edstup k chvostovej \u010dasti abecedy.<\/p>\n<p>Na odstr\u00e1nenie tohto probl\u00e9mu som ru\u010dne pre\u0161iel niektor\u00e9 bloky, ktor\u00e9 zodpovedaj\u00fa r\u00f4znym jazykov, a uviedol pre nich posunutie pomocnej abecedy vo vn\u00fatri hlavnej. Latinku som, na v\u00fdnimku, \u00faplne preusporiadal podobne ako base64.<\/p>\n<p><img decoding=\"async\" alt=\"E\u0161te jeden bicykel: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8\" src=\"\/wp-content\/uploads\/2020\/10\/d191a3bb17403e99d506dbd008b63159.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<h2>Fin\u00e1lne \u00fapravy<\/h2>\n<p>\nPo\u010fme sa nakoniec zamyslie\u0165, kde e\u0161te m\u00f4\u017eeme nie\u010do doladi\u0165.<\/p>\n<p>V\u0161imnime si, \u017ee form\u00e1t <code><b>101xxxxx xxxxxxxx xxxxxxxx<\/b><\/code> umo\u017e\u0148uje k\u00f3dova\u0165 \u010d\u00edsla a\u017e do <code><b>0x1FFFFF<\/b><\/code>, zatia\u013e \u010do Unicode kon\u010d\u00ed sk\u00f4r, na <code><b>0x10FFFF<\/b><\/code>. In\u00fdmi slovami, posledn\u00fd k\u00f3dov\u00fd bod bude reprezentovan\u00fd ako <code><b>10110000 11111111 11111111<\/b><\/code>. Tak\u017ee m\u00f4\u017eeme poveda\u0165, \u017ee ak m\u00e1 prv\u00fd byte tvar <code><b>1011xxxx<\/b><\/code> (kde <code><b>xxxx<\/b><\/code> je viac ako 0), znamen\u00e1 to nie\u010do in\u00e9. Napr\u00edklad, m\u00f4\u017eeme tam prida\u0165 \u010fal\u0161\u00edch 15 symbolov, ktor\u00e9 s\u00fa neust\u00e1le k dispoz\u00edcii na k\u00f3dovanie jedn\u00fdm bytom, ale rozhodol som sa \u00eds\u0165 inou cestou.<\/p>\n<p>Pozrieme sa na tie bloky Unicode, ktor\u00e9 teraz vy\u017eaduj\u00fa tri byty. V z\u00e1sade, ako u\u017e bolo povedan\u00e9, s\u00fa to \u010d\u00ednske znaky \u2014 ale s nimi je \u0165a\u017ek\u00e9 nie\u010do urobi\u0165, je ich 21 tis\u00edc. Ale uletela tam aj hiragana s katakanou \u2014 a t\u00fdch u\u017e nie je ve\u013ea, menej ako dvesto. A ke\u010f\u017ee sme si spomenuli na Japoncov \u2014 tam le\u017eia aj emoji (v skuto\u010dnosti s\u00fa roztrhnut\u00e9 po celom Unicode, ale hlavn\u00e9 bloky s\u00fa v rozmedz\u00ed <code><b>0x1F300<\/b><\/code> \u2013 <code><b>0x1FBFF<\/b><\/code>). Ak si pomysl\u00edme, \u017ee teraz existuj\u00fa emoji, ktor\u00e9 s\u00fa zlo\u017een\u00e9 z viacer\u00fdch k\u00f3dov\u00fdch bodov (napr\u00edklad emoji \u200d\u200d\u200d<noindex><a rel=\"nofollow\" href=\"https:\/\/emojipedia.org\/family-woman-woman-girl-boy\/\"><img decoding=\"async\" alt=\"E\u0161te jeden bicykel: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8\" src=\"\/wp-content\/uploads\/2020\/10\/76cd12423b241cc316af80f03be4348f.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex> sa sklad\u00e1 a\u017e zo 7 k\u00f3dov!), je naozaj \u0161koda m\u00ed\u0148a\u0165 na ka\u017ed\u00fd po tri bajty (7\u00d73 = 21 bajtov za jeden symbol, to je hr\u00f4za).<\/p>\n<p>Preto vyber\u00e1me nieko\u013eko vybran\u00fdch rozsahov, ktor\u00e9 zodpovedaj\u00fa emoji, hiragane a katakane, pre\u010d\u00edslujeme ich do jedn\u00e9ho kontinu\u00e1lneho zoznamu a k\u00f3dujeme vo forme dvoch bajtov namiesto troch:<\/p>\n<p><code><b>1011xxxx xxxxxxxx<\/b><\/code> <\/p>\n<p>Skvel\u00e9: vy\u0161\u0161ie uveden\u00e9 emoji \u200d\u200d\u200d<noindex><a rel=\"nofollow\" href=\"https:\/\/emojipedia.org\/family-woman-woman-girl-boy\/\"><img decoding=\"async\" alt=\"E\u0161te jeden bicykel: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8\" src=\"\/wp-content\/uploads\/2020\/10\/b9900c78dda5d8e596e3751021b4d35d.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex>, ktor\u00e9 pozost\u00e1va zo 7 k\u00f3dov\u00fdch bodov, v UTF-8 zaber\u00e1 25 bajtov, a my sme ho zmestili do <strong>14<\/strong> (presne po dva bajty na ka\u017ed\u00fd k\u00f3dov\u00fd bod). Mimochodom, Habr sa rozhodol ho nezobrazi\u0165 (ani v starom, ani v novom editore), tak\u017ee som ho musel vlo\u017ei\u0165 ako obr\u00e1zok.<\/p>\n<p>Sk\u00fasime opravi\u0165 e\u0161te jeden probl\u00e9m. Ako si pam\u00e4t\u00e1me, hlavn\u00e1 abeceda je v podstate <strong>horn\u00fdch 6 bitov<\/strong>, ktor\u00e9 dr\u017e\u00edme v pam\u00e4ti, a prilepujeme k\u00f3d ka\u017ed\u00e9ho \u010fal\u0161ieho dek\u00f3dovan\u00e9ho symbolu. V pr\u00edpade \u010d\u00ednskych hieroglyfov, ktor\u00e9 s\u00fa v bloku <code><b>0x4E00<\/b><\/code> \u2013 <code><b>0x9FFF<\/b><\/code>, je to bu\u010f bit 0, alebo 1. To nie je ve\u013emi pohodln\u00e9: budeme musie\u0165 neust\u00e1le prep\u00edna\u0165 abecedu medzi t\u00fdmito dvoma hodnotami (t.j. m\u00ed\u0148a\u0165 po tri bajty). Ale v\u0161imnime si, \u017ee v dlhom re\u017eime m\u00f4\u017eeme z k\u00f3du odpo\u010d\u00edta\u0165 po\u010det symbolov, ktor\u00e9 k\u00f3dujeme pomocou kr\u00e1tkeho re\u017eimu (po v\u0161etk\u00fdch vy\u0161\u0161ie uveden\u00fdch fint\u00e1ch to je 10240) \u2014 potom sa rozsah hieroglyfov posunie k <code><b>0x2600<\/b><\/code> \u2013 <code><b>0x77FF<\/b><\/code>, a v tomto pr\u00edpade bud\u00fa na celom tomto rozsahu horn\u00e9 6 bity (z 21) rovn\u00e9 0. Tak\u017ee sekvencie hieroglyfov bud\u00fa pou\u017e\u00edva\u0165 po dva bajty na hieroglyf (\u010do je optim\u00e1lne pre tak ve\u013ek\u00fd rozsah), bez potreby prepn\u00fa\u0165 abecedu. <\/p>\n<h2>Alternat\u00edvne rie\u0161enia: SCSU, BOCU-1<\/h2>\n<p>\nZnalci Unicode, len \u010do si pre\u010d\u00edtaj\u00fa n\u00e1zov \u010dl\u00e1nku, pravdepodobne pon\u00e1h\u013eaj\u00fa pripomen\u00fa\u0165, \u017ee priamo medzi \u0161tandardmi Unicode existuje <noindex><a rel=\"nofollow\" href=\"https:\/\/www.unicode.org\/reports\/tr6\/tr6-4.html\">Standard Compression Scheme for Unicode<\/a><\/noindex> (SCSU), ktor\u00fd popisuje sp\u00f4sob k\u00f3dovania ve\u013emi podobn\u00fd tomu, ktor\u00fd je pop\u00edsan\u00fd v \u010dl\u00e1nku.<\/p>\n<p>Prizn\u00e1m sa \u00faprimne: o jeho existencii som sa dozvedel a\u017e po tom, \u010do som sa hlboko ponoril do p\u00edsania svojho rie\u0161enia. Keby som o \u0148om vedel od za\u010diatku, pravdepodobne by som sa pok\u00fasil nap\u00edsa\u0165 jeho implement\u00e1ciu namiesto vym\u00fd\u0161\u013eania vlastn\u00e9ho pr\u00edstupu.<\/p>\n<p>Zauj\u00edmav\u00e9 je, \u017ee SCSU vyu\u017e\u00edva n\u00e1pady, ktor\u00e9 s\u00fa ve\u013emi podobn\u00e9 t\u00fdm, ku ktor\u00fdm som dospel s\u00e1m (namiesto pojmu \u201ealfab\u00e9ty\u201c sa tam pou\u017e\u00edvaj\u00fa \u201eokn\u00e1\u201c, a je ich viac ako u m\u0148a). Z\u00e1rove\u0148 m\u00e1 tento form\u00e1t aj nev\u00fdhody: je o nie\u010do bli\u017e\u0161ie k algoritmom kompresie ako k\u00f3dovania. Konkr\u00e9tne, \u0161tandard pon\u00faka mno\u017estvo sp\u00f4sobov reprezent\u00e1cie, ale nehovor\u00ed, ako vybra\u0165 z nich optim\u00e1lny \u2013 na to mus\u00ed enk\u00f3der aplikova\u0165 nejak\u00e9 heuristiky. Tak\u017ee SCSU-enk\u00f3der, ktor\u00fd poskytuje dobr\u00e9 balenie, bude zlo\u017eitej\u0161\u00ed a objemnej\u0161\u00ed ako m\u00f4j algoritmus.<\/p>\n<p>Na porovnanie som preniesol relat\u00edvne jednoduch\u00fa implement\u00e1ciu SCSU do JavaScriptu \u2013 objemom k\u00f3du sa uk\u00e1zala porovnate\u013en\u00e1 s moj\u00edm UTF-C, ale v nieko\u013ek\u00fdch pr\u00edpadoch dosiahla v\u00fdsledky o desiatky percent hor\u0161ie (niekedy m\u00f4\u017ee aj prevy\u0161ova\u0165, ale nie mnoh\u00fdmi). Napr\u00edklad texty v hebrej\u010dine a gr\u00e9\u010dtine k\u00f3doval UTF-C o <strong>60 % lep\u0161ie ako SCSU.<\/strong> (pravdepodobne kv\u00f4li ich kompaktn\u00fdm abeced\u00e1m).<\/p>\n<p>Samostatne dod\u00e1m, \u017ee okrem SCSU existuje aj in\u00fd sp\u00f4sob kompaktn\u00e9ho zobrazenia Unicode \u2013 <noindex><a rel=\"nofollow\" href=\"https:\/\/en.wikipedia.org\/wiki\/Binary_Ordered_Compression_for_Unicode\">BOCU-1<\/a><\/noindex>, ale jeho cie\u013eom je kompatibilita s MIME (\u010do som nepotreboval), a pou\u017e\u00edva trochu in\u00fd pr\u00edstup k k\u00f3dovaniu. Jeho \u00fa\u010dinnos\u0165 som nehodnotil, ale zd\u00e1 sa mi, \u017ee nebude vy\u0161\u0161ia ako SCSU.<\/p>\n<h2>Mo\u017en\u00e9 vylep\u0161enia<\/h2>\n<p>\nM\u00f4j algoritmus nie je univerz\u00e1lny by design (v tomto, asi, s\u00fa moje ciele najviac odli\u0161n\u00e9 od cie\u013eov konsorcia Unicode). U\u017e som spomenul, \u017ee bol vyv\u00edjan\u00fd preva\u017ene na jednu \u00falohu (ukladanie viacjazy\u010dn\u00e9ho slovn\u00edka v prefixovom strome) a niektor\u00e9 jeho charakteristiky sa nemusia dobre hodi\u0165 pre in\u00e9 \u00falohy. Ale fakt, \u017ee nie je \u0161tandardom, m\u00f4\u017ee by\u0165 aj pozit\u00edvom \u2013 <strong>m\u00f4\u017eete ho \u013eahko prisp\u00f4sobi\u0165 svojim potreb\u00e1m.<\/strong>.<\/p>\n<p>Napr\u00edklad, je zrejm\u00e9, \u017ee je mo\u017en\u00e9 zbavi\u0165 sa existencie stavu, urobi\u0165 k\u00f3dovanie stateless \u2013 jednoducho neaktualizova\u0165 premenn\u00e9 <code><b>vyp\u00edna\u010de<\/b><\/code>, <code><b>auxOffs<\/b><\/code> a <code><b>is21Bit<\/b><\/code> v enk\u00f3deri a dek\u00f3deri. V takom pr\u00edpade nebude mo\u017en\u00e9 efekt\u00edvne bali\u0165 sekvencie znakov jednej abecedy, zato bude zaru\u010den\u00e9, \u017ee ten ist\u00fd znak sa v\u017edy k\u00f3duje rovnak\u00fdmi bajtmi, bez oh\u013eadu na kontext.<\/p>\n<p>Okrem toho je mo\u017en\u00e9 prisp\u00f4sobi\u0165 kod\u00e9r na konkr\u00e9tny jazyk, zmenou predvolen\u00e9ho stavu \u2013 napr\u00edklad, orientovan\u00edm na rusk\u00e9 texty nastavi\u0165 na za\u010diatku enk\u00f3deru a dek\u00f3deru. <code><b>offs = 0x0400<\/b><\/code> a <code><b>auxOffs = 0<\/b><\/code>. Najm\u00e4 to d\u00e1va zmysel v pr\u00edpade stateless re\u017eimu. Celkovo to bude vyzera\u0165 ako pou\u017e\u00edvanie starej osembitovej k\u00f3dovania, len to neodn\u00edma mo\u017enos\u0165 vklada\u0165 znaky z cel\u00e9ho Unicode pod\u013ea potreby.<\/p>\n<p>\u010eal\u0161ia nev\u00fdhoda, o ktorej som u\u017e spom\u00ednal \u2014 v obsiahlym texte k\u00f3dovanom v UTF-C nie je r\u00fdchly sp\u00f4sob, ako n\u00e1js\u0165 hranicu znaku, ktor\u00fd je najbli\u017e\u0161\u00ed k \u013eubovo\u013en\u00e9mu bytu. Odrezan\u00edm posledn\u00fdch, povedzme, 100 bytov z k\u00f3dovan\u00e9ho bufferu riskujete, \u017ee dostanete odpad, s ktor\u00fdm niet \u010do robi\u0165. Na uchov\u00e1vanie viacgigabajtov\u00fdch logov k\u00f3dovanie nie je ur\u010den\u00e9, ale celkovo to m\u00f4\u017eeme opravi\u0165. Byt <code><b>0xBF<\/b><\/code> nikdy by sa nemal objavi\u0165 ako prv\u00fd byt (ale m\u00f4\u017ee by\u0165 druh\u00fd alebo tret\u00ed). Preto pri k\u00f3dovan\u00ed m\u00f4\u017eete vlo\u017ei\u0165 sekvenciu <code><b>0xBF 0xBF 0xBF<\/b><\/code> ka\u017ed\u00fdch, povedzme, 10 Kb \u2014 potom pri potrebe n\u00e1js\u0165 hranicu sta\u010d\u00ed preh\u013eada\u0165 vybran\u00fd kus, k\u00fdm nen\u00e1jdete podobn\u00fd marker. Po poslednom <code><b>0xBF<\/b><\/code> zaru\u010dene bude za\u010diatok znaku. (Pri dek\u00f3dovan\u00ed t\u00fato sekvenciu z troch bytov, samozrejme, treba ignorova\u0165.)<\/p>\n<h2>Na z\u00e1ver<\/h2>\n<p>\nAk ste do\u010d\u00edtali a\u017e sem - blaho\u017eel\u00e1m! D\u00fafam, \u017ee ste, rovnako ako ja, zistili nie\u010do nov\u00e9 (alebo si osvie\u017eili pam\u00e4\u0165) o \u0161trukt\u00fare Unicode.<\/p>\n<p><img decoding=\"async\" alt=\"E\u0161te jeden bicykel: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8\" src=\"\/wp-content\/uploads\/2020\/10\/f14b2d815b06a7fda7b77c0a32e7eb75.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Demon\u0161tra\u010dn\u00e1 str\u00e1nka. Na pr\u00edklade hebrej\u010diny s\u00fa vidite\u013en\u00e9 v\u00fdhody ako oproti UTF-8, tak aj oproti SCSU.<\/i><\/p>\n<p>Nehodlajte pova\u017eova\u0165 vy\u0161\u0161ie uveden\u00e9 \u00favahy za \u00fatok na normy. Av\u0161ak celkovo som spokojn\u00fd s v\u00fdsledkami svojich pr\u00e1c, preto som r\u00e1d, \u017ee sa o ne <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/deNULL\/utf-c\">podel\u00edm<\/a><\/noindex>: napr\u00edklad, JS kni\u017enica v minifikovanej podobe v\u00e1\u017ei len 1710 bytov (a samozrejme nem\u00e1 \u017eiadne z\u00e1vislosti). Ako som u\u017e spom\u00ednal, s jej fungovan\u00edm sa m\u00f4\u017eete obozn\u00e1mi\u0165 na <noindex><a rel=\"nofollow\" href=\"https:\/\/denull.github.io\/utf-c\/\">demon\u0161tra\u010dnej str\u00e1nke<\/a><\/noindex> (tam je aj sada textov, na ktor\u00fdch ju m\u00f4\u017eete porovna\u0165 s UTF-8 a SCSU).<\/p>\n<p>Na z\u00e1ver op\u00e4\u0165 upozorn\u00edm na pr\u00edpady, kedy by ste mali pou\u017e\u00edva\u0165 UTF-C <b>nie<\/b>:<\/p>\n<ul>\n<li>Ak s\u00fa va\u0161e re\u0165azce dostato\u010dne dlh\u00e9 (od 100-200 znakov). V takom pr\u00edpade by ste mali prem\u00fd\u0161\u013ea\u0165 o aplik\u00e1cii kompresn\u00fdch algoritmov ako deflate.<\/li>\n<li>Ak potrebujete <em>ASCII transparentnos\u0165<\/em>, teda pre v\u00e1s je d\u00f4le\u017eit\u00e9, aby sa v k\u00f3dovan\u00fdch sekvenci\u00e1ch nevyskytovali ASCII k\u00f3dy, ktor\u00e9 neboli v p\u00f4vodnom re\u0165azci. T\u00fdmto potreb\u00e1m sa m\u00f4\u017ee vyhn\u00fa\u0165, ak pri interakcii s extern\u00fdmi API (napr\u00edklad pri pr\u00e1ci s datab\u00e1zou) odovzd\u00e1te v\u00fdsledok k\u00f3dovania ako abstraktn\u00fa mno\u017einu bajtov, nie ako re\u0165azce. Inak riskujete, \u017ee z\u00edskate neo\u010dak\u00e1van\u00e9 zranite\u013enosti.<\/li>\n<li>Ak chcete ma\u0165 mo\u017enos\u0165 r\u00fdchlo n\u00e1js\u0165 hranice znakov pri \u013eubovo\u013enom posune (napr\u00edklad pri po\u0161koden\u00ed \u010dasti re\u0165azca). M\u00f4\u017eete to urobi\u0165, ale iba prehliadnut\u00edm re\u0165azca od za\u010diatku (alebo aplikovan\u00edm \u00fapravy pop\u00edsanej v predch\u00e1dzaj\u00facej \u010dasti).<\/li>\n<li>Ak potrebujete r\u00fdchlo vykon\u00e1va\u0165 oper\u00e1cie na obsahu re\u0165azcov (triedi\u0165 ich, h\u013eada\u0165 v nich podre\u0165azce, konkatenova\u0165). Preto je potrebn\u00e9 najprv re\u0165azce dek\u00f3dova\u0165, a teda UTF-C bude pomal\u0161\u00ed ako UTF-8 v t\u00fdchto pr\u00edpadoch (ale r\u00fdchlej\u0161\u00ed ako algoritmy kompresie). Ke\u010f\u017ee ten ist\u00fd re\u0165azec je v\u017edy k\u00f3dovan\u00fd rovnako, presn\u00e9 porovn\u00e1vanie dek\u00f3dovania to nevy\u017eaduje, m\u00f4\u017ee sa vykon\u00e1va\u0165 po bajtoch.<\/li>\n<\/ul>\n<p><b>Aktualiz\u00e1cia:<\/b> pou\u017e\u00edvate\u013e <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/users\/tyomitch\/\"><b>tyomitch<\/b><\/a><\/noindex> <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/521110\/#comment_22139258\">v koment\u00e1roch ni\u017e\u0161ie<\/a><\/noindex> s\u00fahrnne som zverejnil graf, ktor\u00fd ukazuje hranicu pou\u017eite\u013enosti UTF-C. Na \u0148om je vidie\u0165, \u017ee UTF-C je efekt\u00edvnej\u0161\u00ed ako algoritmus v\u0161eobecn\u00e9ho \u00fa\u010delu (vari\u00e1cie LZW), pokia\u013e je balen\u00fd re\u0165azec krat\u0161\u00ed. <b>~140 znakov<\/b> (pravda, poznamen\u00e1m, \u017ee porovnanie bolo veden\u00e9 na jednom texte; pre in\u00e9 jazyky sa v\u00fdsledok m\u00f4\u017ee l\u00ed\u0161i\u0165).<br \/>\n<img decoding=\"async\" alt=\"E\u0161te jeden bicykel: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8\" src=\"\/wp-content\/uploads\/2020\/10\/0bc9f35ad2757d656801c6466dda09a8.jpeg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>Zdroj: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/521110\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0415\u0441\u043b\u0438 \u0432\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a \u0438 \u043f\u0435\u0440\u0435\u0434 \u0432\u0430\u043c\u0438 \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u0434\u0430\u0447\u0430 \u0432\u044b\u0431\u043e\u0440\u0430 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u043a\u0438, \u0442\u043e \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u0431\u0443\u0434\u0435\u0442 \u042e\u043d\u0438\u043a\u043e\u0434. \u041a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430, \u043d\u043e \u0447\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u0442\u0443\u0442 \u0442\u043e\u0436\u0435 \u0435\u0441\u0442\u044c \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u044b\u0439 \u043e\u0442\u0432\u0435\u0442 \u2014 UTF-8. \u041e\u043d \u0445\u043e\u0440\u043e\u0448 \u0442\u0435\u043c, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u042e\u043d\u0438\u043a\u043e\u0434\u0430, \u043d\u0435 \u0442\u0440\u0430\u0442\u044f \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u0431\u0430\u0439\u0442 \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432. \u041f\u0440\u0430\u0432\u0434\u0430, \u0434\u043b\u044f \u044f\u0437\u044b\u043a\u043e\u0432, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u0445 \u043d\u0435 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":95912,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-95911","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.4 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0415\u0441\u043b\u0438 \u0432\u044b.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/sk\/blog\/administrirovanie\/eshhyo-odin-velosiped-hranim-yunikodnye-stroki-na-30-60-kompaktnee-chem-utf-8\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"sk_SK\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0415\u0449\u0451 \u043e\u0434\u0438\u043d \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434: \u0445\u0440\u0430\u043d\u0438\u043c \u044e\u043d\u0438\u043a\u043e\u0434\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u043d\u0430 30-60% \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u0435\u0435, \u0447\u0435\u043c UTF-8 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0415\u0441\u043b\u0438 \u0432\u044b.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/sk\/blog\/administrirovanie\/eshhyo-odin-velosiped-hranim-yunikodnye-stroki-na-30-60-kompaktnee-chem-utf-8\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-10-04T23:42:09+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-10-04T23:42:09+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47E\u0161te jeden pokus: uchov\u00e1vame unicode re\u0165azce o 30-60 % kompaktnej\u0161ie ako UTF-8 | ProHoster","description":"Ak v\u00e1m.","canonical_url":"https:\/\/prohoster.info\/sk\/blog\/administrirovanie\/eshhyo-odin-velosiped-hranim-yunikodnye-stroki-na-30-60-kompaktnee-chem-utf-8","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sk_SK","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0415\u0449\u0451 \u043e\u0434\u0438\u043d \u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434: \u0445\u0440\u0430\u043d\u0438\u043c \u044e\u043d\u0438\u043a\u043e\u0434\u043d\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u043d\u0430 30-60% \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u0435\u0435, \u0447\u0435\u043c UTF-8 | ProHoster","og:description":"\u0415\u0441\u043b\u0438 \u0432\u044b.","og:url":"https:\/\/prohoster.info\/sk\/blog\/administrirovanie\/eshhyo-odin-velosiped-hranim-yunikodnye-stroki-na-30-60-kompaktnee-chem-utf-8","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-10-04T23:42:09+00:00","article:modified_time":"2020-10-04T23:42:09+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"95911","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 10:55:40","updated":"2022-09-29 03:35:04","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/posts\/95911","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/comments?post=95911"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/posts\/95911\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/media\/95912"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/media?parent=95911"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/categories?post=95911"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sk\/wp-json\/wp\/v2\/tags?post=95911"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}