もう 30 ぀のバむク: Unicode 文字列を UTF-60 よりも 8  XNUMX% コンパクトに保存したす

もう 30 ぀のバむク: Unicode 文字列を UTF-60 よりも 8  XNUMX% コンパクトに保存したす

あなたが開発者で、゚ンコヌディングを遞択するずいう課題に盎面しおいる堎合、ほずんどの堎合、Unicode が適切な゜リュヌションずなるでしょう。 具䜓的な衚珟方法はコンテキストによっお異なりたすが、ほずんどの堎合、ここでも普遍的な答え、぀たり UTF-8 が存圚したす。 これの良い点は、費甚をかけずにすべおの Unicode 文字を䜿甚できるこずです。 あたりにも ほずんどの堎合、バむト数が倚くなりたす。 確かに、ラテン文字以䞊のものを䜿甚する蚀語では、少なくずも「倚すぎない」ずいうこずです。 XNUMX文字あたりXNUMXバむト。 䜿甚できる文字数が 256 文字に制限されおいる先史時代の゚ンコヌディングに戻らずに、もっずうたくできるでしょうか?

以䞋では、この質問に答えるための私の詊みを理解し、UTF-8 のような冗長性を远加するこずなく、䞖界䞭のほずんどの蚀語で行を保存できる比范的単玔なアルゎリズムを実装するこずを提案したす。

免責事項。 すぐにいく぀かの重芁な予玄をしおおきたす。 説明されおいる゜リュヌションは、UTF-8 の汎甚的な代替ずしお提䟛されおいたせん。、これは限られたケヌスのリストにのみ適しおおり (詳现は埌述したす)、いかなる堎合でも、サヌドパヌティ API (それに぀いおさえ知らない) ずの察話に䜿甚すべきではありたせん。 ほずんどの堎合、汎甚圧瞮アルゎリズム (deflate など) は、倧量のテキスト デヌタをコンパクトに保存するのに適しおいたす。 さらに、すでに゜リュヌションを䜜成しおいる途䞭で、同じ問題を解決する Unicode 自䜓の既存の暙準を芋぀けたした。これはやや耇雑です (そしお倚くの堎合、より悪いものです)。しかし、それでも受け入れられおいる暙準であり、単なる定矩ではありたせん。䞀緒に膝の䞊に。 圌のこずに぀いおもお話したす。

Unicode ず UTF-8 に぀いお

たず、それが䜕であるかに぀いお少し説明したす Unicode О UTF-8.

ご存知のずおり、か぀おは 8 ビット ゚ンコヌディングが䞀般的でした。 これらを䜿甚するず、すべおが簡単になりたした。256 文字に 0 から 255 たでの数字を付けるこずができ、0 から 255 たでの数字は明らかに 7 バむトずしお衚すこずができたす。 最初に戻るず、ASCII ゚ンコヌドは完党に 8 ビットに制限されおいるため、バむト衚珟の最䞊䜍ビットはれロであり、ほずんどの XNUMX ビット ゚ンコヌドず互換性がありたす (「䞊䜍」のみが異なりたす)。の郚分、最䞊䜍ビットは XNUMX です)。

Unicode はこれらの゚ンコヌディングずどのように異なりたすか?たた、Unicode に非垞に倚くの特定の衚珟 (UTF-8、UTF-16 (BE および LE)、UTF-32) が関連付けられおいるのはなぜですか? 順番に敎理しおみたしょう。

基本的な Unicode 暙準では、文字 (堎合によっおは文字の個々のコンポヌネント) ずその数倀の間の察応関係のみが蚘述されおいたす。 そしお、この暙準には倚くの可胜な数倀がありたす - 0x00 ЎП 0x10FFFF (1 個)。 このような範囲の数倀を倉数に入れたい堎合、114 バむトでも 112 バむトでも十分ではありたせん。 そしお、私たちのプロセッサは 1 バむトの数倀を扱うようにあたり蚭蚈されおいないため、2 文字あたり最倧 4 バむトを䜿甚するこずになりたす。 これがUTF-32なのですが、この「無駄」があるからこそこの圢匏が普及しないのです。

幞いなこずに、Unicode 内の文字の順序はランダムではありたせん。 セット党䜓は17むンチに分かれおいたす。飛行機"、それぞれに 65536 (0x10000«コヌドポむント」 ここでの「コヌドポむント」の抂念は簡単に蚀うず、 文字番号、Unicodeによっお割り圓おられたす。 しかし、䞊で述べたように、Unicode では個々の文字だけでなく、そのコンポヌネントやサヌビス マヌクにも番号が付けられたす (そしお、堎合によっおは番号にたったく察応しないこずもありたす。おそらく圓面は、これは私たちにずっおはそれほど重芁ではありたせん)。蚘号ではなく、垞に数字自䜓の数に぀いお具䜓的に話すのがより正確です。 ただし、以䞋では、簡朔にするために、「コヌド ポむント」ずいう甚語を暗瀺するために、「シンボル」ずいう蚀葉を頻繁に䜿甚したす。

もう 30 ぀のバむク: Unicode 文字列を UTF-60 よりも 8  XNUMX% コンパクトに保存したす
Unicode プレヌン。 ご芧のずおり、そのほずんど (面 4  13) はただ䜿甚されおいたせん。

最も泚目すべきこずは、すべおの䞻芁な「パルプ」がれロ面にあるこずです。これは「」ず呌ばれたす。基本倚蚀語プレヌン"。行に珟代蚀語 (䞭囜語を含む) のテキストが含たれおいる堎合、この平面を超えるこずはできたせん。ただし、Unicode の残りの郚分を切り取るこずもできたせん。たずえば、絵文字は䞻に行の最埌にありたす。次の飛行機ですよ」補足倚蚀語面「から䌞びおいたす 0x10000 ЎП 0x1FFFF。 したがっお、UTF-16 では次のようになりたす。すべおの文字が以䞋の範囲に含たれたす。 基本倚蚀語プレヌン、察応する XNUMX バむトの数倀を䜿甚しお「そのたた」゚ンコヌドされたす。 ただし、この範囲の数倀の䞀郚は特定の文字をたったく瀺しおいたせんが、このバむトのペアの埌に別のバむトを考慮する必芁があるこずを瀺しおいたす。これらの XNUMX バむトの倀を組み合わせるこずで、以䞋の範囲をカバヌする数倀が埗られたす。有効な Unicode 範囲党䜓。 この考え方は「代理カップル」ず呌ばれおおり、聞いたこずがあるかもしれたせん。

したがっお、UTF-16 では、「コヌド ポむント」ごずに 8 バむト、たたは (非垞にたれなケヌスでは) XNUMX バむトが必芁になりたす。 これは、垞に XNUMX バむトを䜿甚するよりは優れおいたすが、ラテン語 (および他の ASCII 文字) をこの方法で゚ンコヌドするず、れロのスペヌスの半分が無駄になりたす。 UTF-XNUMX はこれを修正するように蚭蚈されおいたす。以前ず同様に、その䞭の ASCII は XNUMX バむトのみを占めたす。 からのコヌド 0x80 ЎП 0x7FF - XNUMXバむト; から 0x800 ЎП 0xFFFF - XNUMX぀、そしおから 0x10000 ЎП 0x10FFFF - 四。 䞀方で、ラテン文字は良くなりたした。ASCII ずの互換性が戻り、分垃は 1 バむトから 4 バむトたでより均等に「分散」されたした。 しかし、残念ながら、ラテン語以倖のアルファベットには UTF-16 ず比べお䜕のメリットもありたせん。倚くのアルファベットでは 32 バむトではなく XNUMX バむトが必芁になりたす。XNUMX バむトのレコヌドでカバヌされる範囲は XNUMX 分の XNUMX に狭たっおいたす。 0xFFFF ЎП 0x7FF、䞭囜語も、たずえばグルゞア語も含たれおいたせん。 キリル文字ずその他の 2 ぀のアルファベット - 䞇歳 - 幞運、XNUMX 文字あたり XNUMX バむト。

なぜこのようなこずが起こるのでしょうか? UTF-8 が文字コヌドをどのように衚珟するかを芋おみたしょう。
もう 30 ぀のバむク: Unicode 文字列を UTF-60 よりも 8  XNUMX% コンパクトに保存したす
数倀を盎接衚すために、ここでは蚘号の付いたビットが䜿甚されたす。 x。 11 バむトのレコヌドには、そのようなビットが (16 個䞭) 21 個しかないこずがわかりたす。 ここの先頭ビットには補助的な機胜しかありたせん。 32 バむトのレコヌドの堎合、24 ビットのうち XNUMX ビットがコヌド ポむント番号に割り圓おられたす。XNUMX バむト (合蚈 XNUMX ビット) で十分であるように芋えたすが、サヌビス マヌカヌが倚くを消費したす。

これはダメですか あたり。 䞀方で、スペヌスを重芖する堎合は、䜙分な゚ントロピヌず冗長性をすべお簡単に陀去できる圧瞮アルゎリズムがありたす。 䞀方、Unicode の目暙は、可胜な限り最も汎甚的なコヌディングを提䟛するこずでした。 たずえば、UTF-8 で゚ンコヌドされた行を、以前は ASCII でのみ機胜しおいたコヌドに委ねるこずができ、実際には存圚しない ASCII 範囲の文字が衚瀺されるこずを心配する必芁はありたせん (結局のずころ、UTF-8 ではすべおれロビットから始たるバむト - これがたさに ASCII です)。 たた、最初からデコヌドせずに、倧きな文字列から小さな末尟を突然切り取りたい堎合 (たたは、砎損したセクションの埌に情報の䞀郚を埩元したい堎合)、文字が始たるオフセットを芋぀けるのは簡単です (これで十分です)ビットプレフィックスを持぀バむトをスキップするには 10).

では、なぜ䜕か新しいものを発明するのでしょうか

同時に、deflate などの圧瞮アルゎリズムはあたり適甚できないが、文字列をコンパクトに保存したい堎合もありたす。 個人的には、構築を考えおいるずきにこの問題に遭遇したした 圧瞮されたプレフィックス ツリヌ 任意の蚀語の単語を含む倧芏暡な蟞曞の堎合。 䞀方で、各単語は非垞に短いため、圧瞮しおも効果がありたせん。 䞀方、私が怜蚎したツリヌ実装は、栌玍された文字列の各バむトが個別のツリヌ頂点を生成するように蚭蚈されおいたため、頂点の数を最小限に抑えるこずが非垞に圹に立ちたした。 私の図曞通で Az.js (のように ピモヌフィ2に基づいおいたす) 同様の問題は簡単に解決できたす - にパックされた文字列 DAWG-蟞曞、そこに保存されおいたす 懐かしいCP1251。 しかし、容易に理解できるように、これは限られたアルファベットに察しおのみうたく機胜したす。䞭囜語の行をそのような蟞曞に远加するこずはできたせん。

これずは別に、このようなデヌタ構造で UTF-8 を䜿甚するずきに生じるもう XNUMX ぀の䞍快なニュアンスに泚意したいず思いたす。 䞊の図は、文字が XNUMX バむトで曞き蟌たれる堎合、その番号に関連するビットが連続せず、XNUMX 察のビットで区切られおいるこずを瀺しおいたす。 10 真ん䞭に 110xxxxx 10xxxxxx。 このため、文字コヌドの6バむト目の䞋䜍XNUMXビットがオヌバヌフロヌした堎合遷移が発生した堎合、 10111111 → 10000000)、最初のバむトも倉曎されたす。 文字「p」はバむトで衚されるこずがわかりたす 0xD0 0xBF、次の「r」はすでに 0xD1 0x80。 プレフィックス ツリヌでは、これにより芪ノヌドが XNUMX ぀に分割され、XNUMX ぀はプレフィックス甚になりたす。 0xD0、もうXNUMX぀は 0xD1 (ただし、キリル文字党䜓は XNUMX バむト目でのみ゚ンコヌドできたす)。

䜕を手に入れたしたか

この問題に盎面しお、私はビットを䜿っおゲヌムをプレむする緎習をし、同時に Unicode 党䜓の構造をもう少しよく理解するこずにしたした。 結果は UTF-C ゚ンコヌド圢匏 (「C」は コンパクト、コヌド ポむントごずに 3 バむト以䞋しか消費せず、倚くの堎合、䜿甚できるのは XNUMX バむトのみです。 ゚ンコヌドされた行党䜓に XNUMX バむト远加。 これは、倚くの非 ASCII アルファベットでは、そのような゚ンコヌディングが次のようになるずいう事実に぀ながりたす。 UTF-30 より 60  8% コンパクト.

゚ンコヌドおよびデコヌドアルゎリズムの実装䟋を次の圢匏で玹介したした。 JavaScript および Go ラむブラリ、コヌド内で自由に䜿甚できたす。 ただし、この圢匏はある意味「自転車」のたたであり、䜿甚はお勧めしたせん。 なぜそれが必芁なのかも知らずに。 これは、本栌的な「UTF-8 の改良」ずいうよりは、ただ実隓にすぎたせん。 それにもかかわらず、コヌドはきちんず簡朔に曞かれおおり、倚数のコメントずテスト カバレッゞが含たれおいたす。

もう 30 ぀のバむク: Unicode 文字列を UTF-60 よりも 8  XNUMX% コンパクトに保存したす
テスト結果ずUTF-8ずの比范

私もそうしたした デモペヌゞでは、アルゎリズムのパフォヌマンスを評䟡できたす。その埌、その原理ず開発プロセスに぀いお詳しく説明したす。

冗長ビットの削陀

もちろん、私は UTF-8 をベヌスにしたした。 この䞭で倉曎できる最初の最も明癜な点は、各バむトのサヌビス ビット数を枛らすこずです。 たずえば、UTF-8 の最初のバむトは垞に次のいずれかで始たりたす。 0、たたは 11 - 接頭蟞 10 次のバむトのみがそれを持っおいたす。 接頭蟞を眮き換えおみたしょう 11 Ма 1、次のバむトではプレフィックスを完党に削陀したす。 䜕が起こるか

0xxxxxxx — 1バむト
10xxxxxx xxxxxxxx - 2バむト
110xxxxx xxxxxxxx xxxxxxxx - 3バむト

埅っお、21 バむトのレコヌドはどこにあるのでしょうか? しかし、それはもう必芁ありたせん。XNUMX バむトで曞き蟌む堎合、珟圚は XNUMX ビットが利甚可胜であり、これは最倧のすべおの数倀に察しお十分です。 0x10FFFF.

私たちはここで䜕を犠牲にしたのでしょうか 最も重芁なこずは、バッファ内の任意の䜍眮から文字境界を怜出するこずです。 任意のバむトをポむントしお、そこから次の文字の先頭を芋぀けるこずはできたせん。 これは私たちの圢匏の制限ですが、実際にはこれが必芁になるこずはほずんどありたせん。 通垞、バッファを最初から実行できたす (特に短い行の堎合)。

2 バむトで蚀語をカバヌする状況も改善されたした。珟圚、14 バむト圢匏では XNUMX ビットの範囲が䞎えられ、これらは最倧で XNUMX ビットのコヌドになりたす。 0x3FFF。 䞭囜人は䞍運だ䞭囜人の性栌は䞻に以䞋のようなものである 0x4E00 ЎП 0x9FFFしかし、グルゞア人や他の倚くの人々はもっず楜しんでいたす - 圌らの蚀語も2文字あたりXNUMXバむトに収たりたす。

゚ンコヌダ状態に入る

次に、線自䜓の性質に぀いお考えおみたしょう。 ほずんどの堎合、蟞曞には同じアルファベットの文字で曞かれた単語が含たれおおり、これは他の倚くのテキストにも圓おはたりたす。 このアルファベットを䞀床指定しお、その䞭の文字の番号だけを指定するず良いでしょう。 Unicode テヌブル内の文字の配眮が圹立぀かどうかを芋おみたしょう。

前述したように、Unicode は次のように分類されたす。 飛行機 それぞれ65536コヌド。 しかし、これはあたり有甚な分割ではありたせん (すでに述べたように、ほずんどの堎合、私たちはれロ平面にいたす)。 さらに興味深いのは、による陀算です。 ブロック。 これらの範囲には固定長がなくなり、より意味のあるものになりたした。原則ずしお、それぞれが同じアルファベットの文字を組み合わせたものになりたす。

もう 30 ぀のバむク: Unicode 文字列を UTF-60 よりも 8  XNUMX% コンパクトに保存したす
ベンガル語のアルファベットの文字を含むブロック。 残念ながら、歎史的な理由により、これはあたり高密床にパッケヌゞ化されおいない䟋です。96 文字が 128 のブロック コヌド ポむントに無秩序に分散されおいたす。

ブロックの先頭ずそのサむズは垞に 16 の倍数です。これは単に䟿宜䞊行われおいるだけです。 さらに、倚くのブロックは 128 たたは 256 の倍数の倀で始たり、終わりたす。たずえば、基本的なキリル文字は 256 バむトを占めたす。 0x0400 ЎП 0x04FF。 これは非垞に䟿利です。プレフィックスを䞀床保存​​するず、 0x04の堎合、任意のキリル文字を XNUMX バむトで曞くこずができたす。 確かに、この方法では ASCII (および䞀般に他の文字) に戻る機䌚を倱うこずになりたす。 したがっお、次のようにしたす。

  1. XNUMXバむト 10yyyyyy yxxxxxxx 蚘号を数字で衚すだけではありたせん yyyyyy yxxxxxxx、しかしたた倉化したす 珟圚のアルファベット Ма yyyyyy y0000000 (぀たり、最䞋䜍ビットを陀くすべおのビットを芚えおいたす 7ビット);
  2. XNUMXバむト 0xxxxxxx これは珟圚のアルファベットの文字です。 手順 1 で蚘憶したオフセットに远加するだけです。アルファベットは倉曎したせんでしたが、オフセットはれロなので、ASCII ずの互換性を維持したした。

3 バむトを必芁ずするコヌドの堎合も同様です。

  1. XNUMXバむト 110yyyyy yxxxxxxx xxxxxxxx 蚘号を数字で瀺す yyyyyy yxxxxxxx xxxxxxxx、 倉化 珟圚のアルファベット Ма yyyyyy y0000000 00000000 (若い子以倖は党郚芚えおた) 15ビット)、珟圚のボックスにチェックを入れたす 長さ モヌド (アルファベットを党角に戻すずき、このフラグをリセットしたす)。
  2. XNUMXバむト 0xxxxxxx xxxxxxxx ロングモヌドでは、珟圚のアルファベットの文字になりたす。 同様に、ステップ 1 のオフセットを䜿甚しおそれを远加したす。唯䞀の違いは、(このモヌドに切り替えたため) XNUMX バむトを読み取るこずです。

いいですね。同じ 7 ビット Unicode 範囲の文字を゚ンコヌドする必芁があるずきに、先頭に 1 バむト䜙分に費やし、文字ごずに合蚈 XNUMX バむトを費やしたす。

もう 30 ぀のバむク: Unicode 文字列を UTF-60 よりも 8  XNUMX% コンパクトに保存したす
以前のバヌゞョンのいずれかを䜿甚しおいたす。 すでに UTF-8 を䞊回るこずがよくありたすが、ただ改善の䜙地がありたす。

䜕が悪いの たず、条件がありたす。 珟圚のアルファベットのオフセット ずチェックボックス ロングモヌド。 これによりさらに制限が加えられ、同じ文字が異なるコンテキストで異なる方法で゚ンコヌドされる可胜性がありたす。 たずえば、郚分文字列の怜玢は、単にバむトを比范するだけではなく、これを考慮しお行う必芁がありたす。 第二に、アルファベットを倉曎するずすぐに、ASCII 文字の゚ンコヌドが悪くなりたした (これはラテン文字だけでなく、スペヌスを含む基本的な句読点も同様です)。アルファベットを再床 0 に倉曎する必芁がありたす。もう䞀床远加のバむトを远加したす (そしお、本題に戻るためにもう XNUMX バむトを远加したす)。

アルファベットは XNUMX 文字が良い、XNUMX 文字が良い

䞊蚘の XNUMX ぀にさらに XNUMX ぀を加えお、ビット プレフィックスを少し倉曎しおみたしょう。

0xxxxxxx — 通垞モヌドでは 1 バむト、ロングモヌドでは 2 バむト
11xxxxxx — 1バむト
100xxxxx xxxxxxxx - 2バむト
101xxxxx xxxxxxxx xxxxxxxx - 3バむト

もう 30 ぀のバむク: Unicode 文字列を UTF-60 よりも 8  XNUMX% コンパクトに保存したす

XNUMX バむトのレコヌドでは、利甚可胜なビットが XNUMX ぀枛りたした。コヌド ポむントは最倧 XNUMX バむトです。 0x1FFFずしない 0x3FFF。 ただし、䟝然ずしお 8 バむトの UTF-XNUMX コヌドよりも著しく倧きく、ほずんどの䞀般的な蚀語はただ収たりたすが、最も顕著な損倱は抜け萜ちおいたす。 ひらがな О カタカナ、日本人は悲しいです。

この新しいコヌドは䜕ですか? 11xxxxxx? これは 64 文字の小さな「隠し堎所」であり、メむンのアルファベットを補完するものであるため、これを補助ず呌びたした (補助 アルファベット。 珟圚のアルファベットを切り替えるず、叀いアルファベットの䞀郚が補助になりたす。 たずえば、ASCII からキリル文字に切り替えたした。スタッシュには、次の内容を含む 64 文字が含たれるようになりたした。 ラテン文字、数字、スペヌス、カンマ (非 ASCII テキストぞの最も頻繁な挿入)。 ASCII に戻すず、キリル文字の䞻芁郚分が補助文字になりたす。

XNUMX ぀のアルファベットにアクセスできるため、アルファベットを切り替えるコストを最小限に抑えながら、倧量のテキストを凊理できたす (句読点を䜿甚するず、ほずんどの堎合 ASCII に戻りたすが、その埌、远加のアルファベットから倚くの非 ASCII 文字が取埗されたす。再床切り替えたす。

ボヌナス: サブアルファベットの接頭蟞 11xxxxxx そしおその初期オフセットを次のように遞択したす 0xC0、CP1252ず郚分的な互換性が埗られたす。 ぀たり、CP1252 で゚ンコヌドされた西ペヌロッパのテキストの倚く (すべおではありたせん) は、UTF-C では同じように芋えたす。

しかし、ここで問題が発生したす。メむンのアルファベットから補助文字をどのように取埗するかです。 同じオフセットをそのたたにするこずもできたすが、残念なこずに、ここでは Unicode 構造がすでに䞍利になっおいたす。 倚くの堎合、アルファベットの䞻芁郚分はブロックの先頭にありたせん (たずえば、ロシアの倧文字「A」には次のコヌドがありたす) 0x0410ただし、キリル文字ブロックは次で始たりたす。 0x0400。 したがっお、最初の 64 文字を隠し堎所に取り蟌むず、アルファベットの末尟の郚分にアクセスできなくなる可胜性がありたす。

この問題を解決するために、さたざたな蚀語に察応するいく぀かのブロックを手動で調べ、それらのメむン アルファベット内の補助アルファベットのオフセットを指定したした。 䟋倖ずしお、ラテン文字は通垞、base64 のように䞊べ替えられたした。

もう 30 ぀のバむク: Unicode 文字列を UTF-60 よりも 8  XNUMX% コンパクトに保存したす

最埌の仕䞊げ

最埌に、他に改善できる点を考えおみたしょう。

圢匏に泚意しおください 101xxxxx xxxxxxxx xxxxxxxx たでの数倀を゚ンコヌドできたす 0x1FFFFF、Unicode はより早く終了したす。 0x10FFFF。 ぀たり、最埌のコヌドポむントは次のように衚されたす。 10110000 11111111 11111111。 したがっお、最初のバむトが次の圢匏である堎合、次のように蚀えたす。 1011xxxx どこ xxxx 0 より倧きい堎合、それは別の意味になりたす。 たずえば、そこにさらに 15 文字を远加しお、垞に XNUMX バむトの゚ンコヌドに利甚できるようにするこずもできたすが、私は別の方法で行うこずにしたした。

21 バむトを必芁ずする Unicode ブロックを芋おみたしょう。 基本的に、すでに述べたように、これらは挢字ですが、XNUMX もの文字があるため、それを䜿っお䜕かをするのは困難です。 しかし、ひらがなずカタカナもそこに飛んできたした - そしおそれらの数はもうそれほど倚くはなく、XNUMX未満です。 そしお、日本語を芚えたので、絵文字もありたす実際、絵文字はUnicodeのさたざたな堎所に散圚しおいたすが、䞻芁なブロックは範囲内にありたす 0x1F300 – 0x1FBFF。 珟圚、耇数のコヌドポむントから䞀床に組み立おられた絵文字があるずいう事実を考えおみおください (たずえば、絵文字 ‍‍‍もう 30 ぀のバむク: Unicode 文字列を UTF-60 よりも 8  XNUMX% コンパクトに保存したす 7 個ものコヌドで構成されおいる堎合、それぞれに 7 バむトを費やすのはたったくの恥ずべきこずになりたす (3 ぀のアむコンのために 21×XNUMX = XNUMX バむト、たさに悪倢です)。

したがっお、絵文字、ひらがな、カタカナに察応する範囲をいく぀か遞択し、番号を付け盎しお XNUMX ぀の連続リストにし、XNUMX バむトではなく XNUMX バむトずしお゚ンコヌドしたす。

1011xxxx xxxxxxxx

玠晎らしい: 前述の ‍‍‍ 絵文字もう 30 ぀のバむク: Unicode 文字列を UTF-60 よりも 8  XNUMX% コンパクトに保存したすは 7 ぀のコヌド ポむントで構成され、UTF-8 では 25 バむトを必芁ずし、次のように収たりたす。 14 (各コヌド ポむントに正確に XNUMX バむト)。 ちなみに、Habr は (叀い゚ディタでも新しい゚ディタでも) ダむゞェストするこずを拒吊したため、画像を挿入する必芁がありたした。

もう XNUMX ぀問題を解決しおみたしょう。 私たちが芚えおいるように、基本的なアルファベットは本質的には 䞊䜍6ビットこれを念頭に眮き、次にデコヌドされた各シンボルのコヌドに貌り付けたす。 ブロック内の挢字の堎合 0x4E00 – 0x9FFF、これはビット 0 たたは 1 のいずれかです。これはあたり䟿利ではありたせん。これら 10240 ぀の倀の間でアルファベットを垞に切り替える必芁がありたす (぀たり、XNUMX バむトを費やしたす)。 ただし、ロング モヌドでは、コヌド自䜓から、ショヌト モヌドを䜿甚しお゚ンコヌドした文字数を差し匕くこずができるこずに泚意しおください (䞊蚘のトリックをすべお実行するず、これは XNUMX になりたす)。そうするず、象圢文字の範囲が にシフトしたす。 0x2600 – 0x77FFこの堎合、この範囲党䜓を通じお、(6 のうちの) 最䞊䜍 21 ビットは 0 に等しくなりたす。したがっお、象圢文字のシヌケンスは、象圢文字ごずに XNUMX バむトを䜿甚したす (これは、このような広い範囲には最適です)。アルファベットが切り替わる原因ずなりたす。

代替゜リュヌション: SCSU、BOCU-1

Unicode の専門家は、この蚘事のタむトルを読んだだけで、Unicode 暙準の䞭に次のものがあるこずをすぐに思い出されるでしょう。 Unicode の暙準圧瞮スキヌム (SCSU)、この蚘事で説明されおいるものず非垞によく䌌た゚ンコヌド方法が説明されおいたす。

正盎に認めたす。私がその存圚を知ったのは、自分の決定を曞くこずに深く没頭した埌でした。 最初からそのこずを知っおいたら、おそらく独自のアプロヌチを考え出すのではなく、実装を曞こうずしたでしょう。

興味深いこずに、SCSU は私が自分で考え出したアむデアず非垞によく䌌たアむデアを䜿甚しおいたす (「アルファベット」の抂念の代わりに、SCSU では「りィンドり」が䜿甚されおおり、私が持っおいるものよりも倚くのアむデアが利甚可胜です)。 同時に、この圢匏には欠点もありたす。゚ンコヌドアルゎリズムよりも圧瞮アルゎリズムに少し近いずいうこずです。 特に、この芏栌では倚くの衚珟方法が提䟛されおいたすが、最適な衚珟方法を遞択する方法に぀いおは芏定されおいたせん。このために、゚ンコヌダはある皮のヒュヌリスティックを䜿甚する必芁がありたす。 したがっお、適切なパッケヌゞングを生成する SCSU ゚ンコヌダは、私のアルゎリズムよりも耇雑で扱いにくいものになりたす。

比范のために、SCSU の比范的単玔な実装を JavaScript に転送したした。コヌド量の点では、UTF-C ず同等であるこずがわかりたしたが、堎合によっおは結果が数十パヌセント悪かったこずもありたす (堎合によっおはそれを超える堎合もありたすが、それほど倚くはありたせん。 たずえば、ヘブラむ語ずギリシャ語のテキストは UTF-C で゚ンコヌドされたした。 SCSUより60%優れおいたす (おそらくアルファベットがコンパクトなため)。

これずは別に、SCSU 以倖にも Unicode をコンパクトに衚珟する別の方法があるこずを付け加えおおきたす。 BOCU-1ですが、これは MIME 互換性 (私には必芁ありたせんでした) を目的ずしおおり、゚ンコヌドに察しお少し異なるアプロヌチを採甚しおいたす。 有効性に぀いおは評䟡しおいたせんが、SCSU よりも高い可胜性は䜎いず思われたす。

考えられる改善点

私が提瀺したアルゎリズムは、蚭蚈䞊普遍的なものではありたせん (おそらく、これが私の目暙が Unicode コン゜ヌシアムの目暙ず最も異なる点です)。 これは䞻に XNUMX ぀のタスク (プレフィックス ツリヌに倚蚀語蟞曞を保存する) のために開発されたものであり、その機胜の䞀郚は他のタスクにはあたり適しおいない可胜性があるこずはすでに述べたした。 しかし、それが暙準ではないずいう事実はプラスになる可胜性がありたす - ニヌズに合わせお簡単に倉曎できたす.

たずえば、明らかな方法ずしお、状態の存圚を取り陀き、ステヌトレスなコヌディングを䜜成できたす。倉数を曎新しないだけです。 offs, auxOffs О is21Bit ゚ンコヌダずデコヌダで。 この堎合、同じアルファベットの文字のシヌケンスを効果的にパックするこずはできたせんが、コンテキストに関係なく、同じ文字が垞に同じバむトで゚ンコヌドされるこずが保蚌されたす。

さらに、デフォルトの状態を倉曎するこずで、゚ンコヌダヌを特定の蚀語に合わせお調敎できたす。たずえば、ロシア語のテキストに焊点を圓お、最初に゚ンコヌダヌずデコヌダヌを蚭定したす。 offs = 0x0400 О auxOffs = 0。 これは、ステヌトレス モヌドの堎合に特に意味がありたす。 䞀般に、これは叀い XNUMX ビット ゚ンコヌディングの䜿甚に䌌おいたすが、必芁に応じおすべおの Unicode から文字を挿入する機胜は削陀されたせん。

前述したもう 100 ぀の欠点は、UTF-C で゚ンコヌドされた倧きなテキストでは、任意のバむトに最も近い文字境界を簡単に芋぀ける方法がないこずです。 ゚ンコヌドされたバッファヌから最埌の、たずえば XNUMX バむトを切り取るず、䜕もできないゎミが発生する危険がありたす。 ゚ンコヌドは、数ギガバむトのログを保存するように蚭蚈されおいたせんが、䞀般的には修正できたす。 バむト 0xBF 決しお最初のバむトずしお出珟しおはなりたせん (ただし、XNUMX 番目たたは XNUMX 番目のバむトである堎合もありたす)。 したがっお、゚ンコヌド時にシヌケンスを挿入できたす。 0xBF 0xBF 0xBF たずえば 10 KB ごず - 境界を芋぀ける必芁がある堎合は、同様のマヌカヌが芋぀かるたで遞択した郚分をスキャンするだけで十分です。 最埌に続いお 0xBF 文字の始たりであるこずが保蚌されおいたす。 (デコヌド時には、この XNUMX バむトのシヌケンスは圓然無芖する必芁がありたす。)

芁玄

ここたで読んでくださった方、おめでずうございたす! あなたも私ず同じように、Unicode の構造に぀いお䜕か新しいこずを孊んだ (たたは蚘憶を新たにした) こずを願っおいたす。

もう 30 ぀のバむク: Unicode 文字列を UTF-60 よりも 8  XNUMX% コンパクトに保存したす
デモペヌゞ。 ヘブラむ語の䟋は、UTF-8 ず SCSU の䞡方に察する利点を瀺しおいたす。

䞊蚘の研究は、芏栌ぞの䟵害ずみなされるべきではありたせん。 しかし、仕事の結果には抂ね満足しおいるので、満足しおいたす。 シェアする: たずえば、瞮小された JS ラむブラリの重さはわずか 1710 バむトです (もちろん䟝存関係はありたせん)。 䞊で述べたように、圌女の䜜品は次の堎所で芋぀けるこずができたす。 デモペヌゞ (UTF-8 および SCSU ず比范できるテキストのセットもありたす)。

最埌に、UTF-C が䜿甚されるケヌスに぀いおもう䞀床泚意しおください。 それほど䟡倀がない:

  • 行が十分に長い堎合 (100  200 文字)。 この堎合、deflate などの圧瞮アルゎリズムの䜿甚を怜蚎する必芁がありたす。
  • 必芁な堎合は ASCII の透過性぀たり、゚ンコヌドされたシヌケンスには、元の文字列に含たれおいない ASCII コヌドが含たれおいないこずが重芁です。 サヌドパヌティ API ず察話するずき (たずえば、デヌタベヌスを操䜜するずき)、゚ンコヌド結果を文字列ずしおではなく抜象的なバむトのセットずしお枡す堎合、この必芁性を回避できたす。 そうしないず、予期しない脆匱性が発生する危険がありたす。
  • 任意のオフセットで文字の境界をすばやく芋぀けたい堎合 (たずえば、行の䞀郚が砎損しおいる堎合)。 これは行を最初からスキャンする (たたは前のセクションで説明した倉曎を適甚する) こずによっおのみ実行できたす。
  • 文字列の内容に察しお操䜜をすばやく実行する必芁がある堎合 (文字列の䞊べ替え、文字列内の郚分文字列の怜玢、連結)。 これには、最初に文字列をデコヌドする必芁があるため、このような堎合、UTF-C は UTF-8 よりも遅くなりたす (ただし、圧瞮アルゎリズムよりは高速です)。 同じ文字列は垞に同じ方法で゚ンコヌドされるため、デコヌドの正確な比范は必芁なく、バむトごずに行うこずができたす。

アップデヌト ナヌザヌ チョミッチ 以䞋のコメントで UTF-C の適甚制限を匷調するグラフを投皿したした。 これは、パックされた文字列が短い限り、UTF-C が汎甚圧瞮アルゎリズム (LZW のバリ゚ヌション) よりも効率的であるこずを瀺しおいたす。 ~140 文字 (ただし、比范は XNUMX ぀のテキストに察しお行われたこずに泚意しおください。他の蚀語では結果が異なる堎合がありたす)。
もう 30 ぀のバむク: Unicode 文字列を UTF-60 よりも 8  XNUMX% コンパクトに保存したす

出所 habr.com

コメントを远加したす