JavaScriptはどのようにUTF-16コードをUTF-8コードに変換しますか?


概要
フロントエンドでバイナリデータを通じてサービスと通信する必要がある場合、バイナリデータの符号化問題が発生する可能性があります.ほとんどのサービス端末の文字列コードタイプはUTF-8であり、JavaScriptの文字列コードタイプはUTF-16であるため、文字列を二つの符号化方式の間で変換できる方法が必要である.
本論文では、utfx.jsというライブラリのコードを分析することにより、UTF 8とUTF 16の二つの符号化方式のJavaScriptにおける変換方法を深く理解するとともに、UniodeにおけるUTF-8とUTF-16の符号化方式の具体的な原理の理解を深める.
本論文の主な内容は以下の通りである.
  • utfx.js APIの簡単な紹介
  • UTF-16符号化は、UTF-8符号化
  • に変換される.
  • UTF-8符号化文字列長計算
  • 実験的機能:window.Text Engcoder
  • UnicodeのUTF-8とUTF-16の二つの符号化方式の具体的な原理を理解していない読者がいたら、私の前のブログであるUnicodeのUTF-8とUTF-16のコードを読むことができます.
    もし読者がこのライブラリに関する変換使用シーンを知りたいなら、私の前のブログWebSocketシリーズのJavaScript文字列はどうやってバイナリデータと相互に変換されますか?
    utfx.js API概要
    具体的なコードの詳細を行う前に、まず私達が紹介したいライブラリ――utfx.jsを調べてみます.私たちはこのライブラリの使い方を知ってこそ、ソースコードをよりよく理解することができます.
    utfx.jsコードは多くないです.全部で8つのAPIインターフェースしかありません.それぞれ:
  • encodeUTF 8:UTF-8符号化された文字列コードをバイナリbytesに変換します.
  • decodeUTF 8:UTF-8をエンコードしたバイナリbytesを城文字列codeコードに復号します.
  • UTF 16 toUTF 8:UTF-16の文字をUTF-8のcodeコードに変換する.
  • UTF 8 toUTF 16:UTF-8のcodeコードをUTF-16の文字に変換する.
  • encodeUT F 16 toUTF 8:UTF-16符号化された文字をUTF-8符号化されたbytesに変換する.
  • decodeUTF 8 toUTF 16:UTF-8の符号化されたbytesをUTF-16の符号化された文字に変換する.
  • calculateCodePoint:UTF-8符号化された文字の長さを計算します.
  • calculateUTF 8:UTF-8コードを格納するために必要なbytesの長さを計算する.
  • calculateUT F 16 a sUTF 8:UTF-16符号化の文字をUTF-8に変換した後に必要な記憶長を計算します.
  • 以下では、代表的なAPIをいくつか選び、その実現された具体的なコードについて分析を行い、この2つの符号化方式を迅速に理解することを助けます.
    UTF-16符号化はUTF-8符号化に変換される.
    UTF-16符号化データをUTF-8符号化データに変換する方法を見てみましょう.
    UTF-16のデータをUTF-8符号化のデータに変換する必要がある場合、最も良い方法は、UTF-16符号化のデータを汎用的なUnicodeに変換し、UTF-8符号化していることに間違いない.UTF 16 toUTF 8とencodeUTF 8法のコードにより具体的に解析した.
    UTF 16 toUTF 8
    この関数名は、UTF-16の符号化されたbytesデータをUTF-8の符号化されたBytesデータに直接変換するように見える.実は、UTF-16が符号化したbytesデータをUnicodeに対応するバイナリデータに変換します.
    /**
     * UTF16     Unicode  
     * @param src    ,   Function,      1 Byte  ,            null
     * @param dst     ,   Function,   Bytes       dst  
     */
    utfx.UTF16toUTF8 = function (src, dst) {
        var c1, c2 = null;
        while (true) {
            //       src    null         
            if ((c1 = c2 !== null ? c2 : src()) === null)
                break;
            
            //Unicode    ,U+D800~U+DFFF         ,              
            if (c1 >= 0xD800 && c1 <= 0xDFFF) {
                if ((c2 = src()) !== null) {
                    //   Unicode     U+FFFF         (  :     U+D800,     U+DC00)
                    if (c2 >= 0xDC00 && c2 <= 0xDFFF) {
                        //    : c1   10 ;   : c2     ;   :     0x10000
                        dst((c1 - 0xD800) * 0x400 + c2 - 0xDC00 + 0x10000);
                        c2 = null; continue;
                    }
                }
            }
            dst(c1);
        }
        if (c2 !== null) dst(c2);
    };
    コードと上のコメントによって、対応コードが分かりますので、ここで過多な説明はしません.続いてユニックコードをUTF-8符号に変換する方法を見ます.
    encodeUTF 8
    この方法は、UnicodeコードをUTF-8符号化変換し、UTF-8符号化されたBytesデータを得ることである.
    /**
     * Unicode     UTF-8  
     * @param src    ,   Function,      1 Byte  ,            null
     * @param dst     ,   Function,   Bytes       dst  
     */
    utfx.encodeUTF8 = function (src, dst) {
        var cp = null;
        if (typeof src === 'number')
            cp = src,
                src = function () {return null;};
        while (cp !== null || (cp = src()) !== null) {
            if (cp < 0x80)
            // 1 byte    
                dst(cp & 0x7F);
            else if (cp < 0x800)
            // 2 byte    
                dst(((cp >> 6) & 0x1F) | 0xC0),
                dst((cp & 0x3F) | 0x80);
            else if (cp < 0x10000)
            // 3 byte    
                dst(((cp >> 12) & 0x0F) | 0xE0),
                dst(((cp >> 6) & 0x3F) | 0x80),
                dst((cp & 0x3F) | 0x80);
            else
            // 4 byte    
                dst(((cp >> 18) & 0x07) | 0xF0),
                dst(((cp >> 12) & 0x3F) | 0x80),
                dst(((cp >> 6) & 0x3F) | 0x80),
                dst((cp & 0x3F) | 0x80);
            cp = null;
        }
    };
    上記のコードはUTF-8符号化規格の方式と基本的に一致しています.もし関連規格を理解していないなら、先に本文の概説で言及した前のブログを読んでもいいです.
    符号化文字列長計算
    Unicodeコードの一列を与えると、変換後のデータストアのどれぐらいの大きさのArayBufferを申請するかを知る必要があります.ちょうど、このライブラリはまた、Unicodeコードの長さまたはUTF-16符号化フォーマットのデータからUTF-8データの記憶長を計算するために提供されている.calculateUTF8calculateUTF16asUTF8の2つの方法を紹介します.
    caculateUTF 8
    この方法は、UnicodeコードによりUTF-8符号に変換した後の記憶長を計算するものである.
    /**
     *   Unicode        UTF-8          
     * @param src    ,   Function,      1 Byte  ,            null
     */
    utfx.calculateUTF8 = function (src) {
        var cp, l = 0;
        while ((cp = src()) !== null)
            //  1 Byte    0~0x7F; 2 Byte    0x80~0x7FF;         0x800~0xFFFF; 4       :0x10000~0x10FFFF
            l += (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4;
        return l;
    };
    上記のコードとUTF-8のコード仕様によって、この幅計算の方法が分かりやすくなります.
    calculateUT F 16 a sUTF 8
    この方法は、UTF 16のデータからUnicodeに変換されたコードを計算し、UTF-8符号に変換した後の記憶長を占める.
    /**
     *   UTF-16   Bytes      Unicode       UTF-8          
     * @param src    ,   Function,      1 Byte  ,            null
     */
    utfx.calculateUTF16asUTF8 = function (src) {
        var n = 0, l = 0;
        utfx.UTF16toUTF8(src, function (cp) {
            ++n; l += (cp < 0x80) ? 1 : (cp < 0x800) ? 2 : (cp < 0x10000) ? 3 : 4;
        });
        return [n, l];
    };
    この方法は、以前に紹介したUTF-16をUnicodeに符号化する方法でUnicodeデータを取得して計算し、Unicodeコードの長さとUTF-8符号化後の長さを返します.
    window.Text EncoderとWindow.Text Decoder
    これは、2つの実験的な新しい構成関数であり、エンコーダ(TextEncodeオブジェクト)とデコーダ(TextDecodeオブジェクト)を作成することによって、JavaScriptにおけるstringタイプとUTF−8符号化データとの相互変換を実現する.
    構成方法はUTF-8符号化に戻ります.使い方は以下の通りです.
    let encoder = new TextEncoder();
    let decoder = new TextDecoder();
    
    let unit8Array = encoder.encode('a'); //     Unit8Array  ——[97]
    let str = decoder.decode(arr); //       'a'    
    現在、この新しい技術の互換性には大きな問題が残っています.Chrome 38、Firefox 19及びOpera 25以上がサポートしています.他の主流のブラウザはIEやSafariなどはまだサポートされていませんので、生産段階では慎重に使う必要があります.
    締め括りをつける
    本論文では、UnicodeにおけるUTF-8とUTF-16の二つの符号化方式を実現したライブラリ――utfx.jsについて部分コード解析を行った.具体的なコードの実現を見ることによって、この二つのコード方式の具体的な仕様と対応する使い方とシーンをよりよく理解できると思います.