web-dev-qa-db-ja.com

UTF8文字列をバイト配列に変換する方法は?

.charCodeAt関数は、キャラクターのUnicodeコードを返します。しかし、代わりにバイト配列を取得したいと思います。文字コードが127を超える場合、文字は2バイト以上で保存されます。

var arr=[];
for(var i=0; i<str.length; i++) {
    arr.Push(str.charCodeAt(i))
}
40
don kaka

UnicodeをUTF-8でエンコードするロジックは、基本的に次のとおりです。

  • 1文字につき最大4バイトを使用できます。可能な限り少ないバイト数が使用されます。
  • U + 007Fまでの文字は1バイトでエンコードされます。
  • マルチバイトシーケンスの場合、最初のバイトの先頭1ビットの数が文字のバイト数を示します。最初のバイトの残りのビットは、文字のビットをエンコードするために使用できます。
  • 継続バイトは10で始まり、他の6ビットは文字のビットをエンコードします。

JavaScript UTF-16文字列をUTF-8でエンコードするためにしばらく前に書いた関数を次に示します。

function toUTF8Array(str) {
    var utf8 = [];
    for (var i=0; i < str.length; i++) {
        var charcode = str.charCodeAt(i);
        if (charcode < 0x80) utf8.Push(charcode);
        else if (charcode < 0x800) {
            utf8.Push(0xc0 | (charcode >> 6), 
                      0x80 | (charcode & 0x3f));
        }
        else if (charcode < 0xd800 || charcode >= 0xe000) {
            utf8.Push(0xe0 | (charcode >> 12), 
                      0x80 | ((charcode>>6) & 0x3f), 
                      0x80 | (charcode & 0x3f));
        }
        // surrogate pair
        else {
            i++;
            // UTF-16 encodes 0x10000-0x10FFFF by
            // subtracting 0x10000 and splitting the
            // 20 bits of 0x0-0xFFFFF into two halves
            charcode = 0x10000 + (((charcode & 0x3ff)<<10)
                      | (str.charCodeAt(i) & 0x3ff));
            utf8.Push(0xf0 | (charcode >>18), 
                      0x80 | ((charcode>>12) & 0x3f), 
                      0x80 | ((charcode>>6) & 0x3f), 
                      0x80 | (charcode & 0x3f));
        }
    }
    return utf8;
}
57
Joni

JavaScript Stringsは UTF-16 に保存されます。 UTF-8を取得するには、Stringを自分で変換する必要があります。

1つの方法は、 encodeURIComponent() を混在させて、URLエンコードされたUTF-8バイトを unescape と組み合わせて、 ecmanautに記載されている

var utf8 = unescape(encodeURIComponent(str));

var arr = [];
for (var i = 0; i < utf8.length; i++) {
    arr.Push(utf8.charCodeAt(i));
}
35

新しい Encoding API を使用すると、UTF-8を簡単にエンコードおよびデコードできます(型付き配列を使用)。

var encoded = new TextEncoder("utf-8").encode("Γεια σου κόσμε");
var decoded = new TextDecoder("utf-8").decode(encoded);

console.log(encoded, decoded);

ブラウザのサポート それほど悪くない 、および polyfill があり、IE11およびEdgeの古いバージョンで動作します。

APIはさまざまなエンコーディングもサポートしています。これを使用して、日本語テキスト(Shift-JIS)をデコード/エンコードします。

new TextDecoder("shift-jis").decode(new Uint8Array(textbuffer))
9
bryc

Google Closureライブラリには、UTF-8およびバイト配列との間で変換する関数があります。ライブラリ全体を使用したくない場合は、 here から関数をコピーできます。完全を期すために、文字列にUTF-8バイト配列に変換するコードは次のとおりです。

goog.crypt.stringToUtf8ByteArray = function(str) {
  // TODO(user): Use native implementations if/when available
  var out = [], p = 0;
  for (var i = 0; i < str.length; i++) {
    var c = str.charCodeAt(i);
    if (c < 128) {
      out[p++] = c;
    } else if (c < 2048) {
      out[p++] = (c >> 6) | 192;
      out[p++] = (c & 63) | 128;
    } else if (
        ((c & 0xFC00) == 0xD800) && (i + 1) < str.length &&
        ((str.charCodeAt(i + 1) & 0xFC00) == 0xDC00)) {
      // Surrogate Pair
      c = 0x10000 + ((c & 0x03FF) << 10) + (str.charCodeAt(++i) & 0x03FF);
      out[p++] = (c >> 18) | 240;
      out[p++] = ((c >> 12) & 63) | 128;
      out[p++] = ((c >> 6) & 63) | 128;
      out[p++] = (c & 63) | 128;
    } else {
      out[p++] = (c >> 12) | 224;
      out[p++] = ((c >> 6) & 63) | 128;
      out[p++] = (c & 63) | 128;
    }
  }
  return out;
};
8
optevo

入力としてのDOMStringに関する質問であり、目標は文字列として解釈される(たとえば、ディスク上のファイルに書き込まれる)UTF-8エンコードされる配列を取得することであると仮定します。

ほぼすべての最新のブラウザー Typed Arrayをサポート であるため、このアプローチがリストされていないと恥ずかしいでしょう:

  • W3C によると、File APIをサポートするソフトウェアはBLOBコンストラクターDOMString sを受け入れる必要があります(参照: String encoding when Blobの構築
  • ファイルリーダー.readAsArrayBuffer()関数を使用して、BlobをArrayBufferに変換できます。
  • DataViewを使用するか、Typed Arrayを作成して、ファイルリーダーで読み取ったバッファーを使用すると、ArrayBufferのすべての単一バイトにアクセスできます。

例:

// Create a Blob with an Euro-char (U+20AC)
var b = new Blob(['€']);
var fr = new FileReader();

fr.onload = function() {
    ua = new Uint8Array(fr.result);
    // This will log "3|226|130|172"
    //                  E2  82  AC
    // In UTF-16, it would be only 2 bytes long
    console.log(
        fr.result.byteLength + '|' + 
        ua[0]  + '|' + 
        ua[1] + '|' + 
        ua[2] + ''
    );
};
fr.readAsArrayBuffer(b);

JSFiddle でそれを試してください。私はまだこれをベンチマークしていませんが、これが入力としての大きなDOMStringsに対して効率的であると想像できます。

6
Rainer Rillke

FileReaderを使用すると、文字列をそのまま保存できます。

文字列をblobに保存し、readAsArrayBuffer()を呼び出します。次に、onload-eventによって配列バッファーが生成され、Uint8Arrayに変換できます。残念ながら、この呼び出しは非同期です。

この小さな機能は次のことに役立ちます。

function stringToBytes(str)
{
    let reader = new FileReader();
    let done = () => {};

    reader.onload = event =>
    {
        done(new Uint8Array(event.target.result), str);
    };
    reader.readAsArrayBuffer(new Blob([str], { type: "application/octet-stream" }));

    return { done: callback => { done = callback; } };
}

次のように呼び出します。

stringToBytes("\u{1f4a9}").done(bytes =>
{
    console.log(bytes);
});

出力:[240, 159, 146, 169]

説明:

JavaScriptはUTF-16とサロゲートペアを使用して、Unicode文字をメモリに格納します。 Unicode文字を生のバイナリバイトストリームに保存するには、エンコードが必要です。通常、ほとんどの場合、UTF-8がこれに使用されます。エンコードを使用しない場合、Unicode文字は保存できません。ASCII 0x7fまで。

FileReader.readAsArrayBuffer()はUTF-8を使用します。

2
Martin Wantke

私は Joniの解 を使用していましたが、うまくいきましたが、これはずっと短いです。

これは MozillaのBase64 Unicodeディスカッション のソリューション#3のatobUTF16()関数に触発されました

function convertStringToUTF8ByteArray(str) {
    let binaryArray = new Uint8Array(str.length)
    Array.prototype.forEach.call(binaryArray, function (el, idx, arr) { arr[idx] = str.charCodeAt(idx) })
    return binaryArray
}
1
jk7