JavaScript文字列のバイト数は?


97

UTF-8でサーバーから送信されたときに約500KのJavaScript文字列があります。JavaScriptでそのサイズを確認するにはどうすればよいですか?

JavaScriptがUCS-2を使用していることは知っています。つまり、1文字あたり2バイトを意味します。しかし、それはJavaScriptの実装に依存しますか?またはページエンコーディングまたは多分コンテンツタイプで?


約 答えはlength * charsizeになるので、あなたの推測は近いです。
glasnt 2010

1
ES6などの最新のJavaScriptは、UCS-2を使用するだけでなく、詳細はこちらをご覧ください:stackoverflow.com/a/46735247/700206
whitneyland 2017年

回答:


36

StringECMA-262 3rd Edition仕様によると、値は実装に依存しません。各文字は、UTF-16テキストの単一の16ビット単位を表します

4.3.16文字列値

文字列値はString型のメンバーであり、0個以上の16ビット符号なし整数値の有限順序シーケンスです。

注各値は通常、UTF-16テキストの単一の16ビット単位を表しますが、言語は、16ビットの符号なし整数であることを除いて、値に制限や要件を課しません。


8
私がその一節を読んだことは、実装の独立性を意味するものではありません。
Paul Biggar 2010

4
UTF-16は保証されておらず、文字列が16ビットintとして格納されているという事実のみが保証されています。
bjornl 2010年

これは、UTF-16に関しては実装にのみ依存します。16ビットの文字記述は普遍的です。
Panzercrisis 2015年

1
私は、Firefoxでも....いくつかの文字列に文字あたり1つのバイトを使用することができ、内部で考えるblog.mozilla.org/javascript/2014/07/21/...
ミハルCharemza

1
UTF-16は、私が読んでいる方法では明示的に許可されいません。UTF-16文字は最大4バイトですが、仕様には「値は16ビットの符号なし整数でなければなりません」と記載されています。これは、JavaScript文字列値がUTF-16のサブセットであることを意味しますが、3バイトまたは4バイトの文字を使用するUTF-16文字列は許可されません。
ホイットニーランド2017年

71

この関数は、渡されたUTF-8文字列のバイトサイズを返します。

function byteCount(s) {
    return encodeURI(s).split(/%..|./).length - 1;
}

ソース

JavaScriptエンジンは、UCS-2またはUTF-16を内部で自由に使用できます。私が知っているほとんどのエンジンはUTF-16を使用していますが、どのような選択をしたとしても、言語の特性に影響を与えないのは実装の詳細にすぎません。

ただし、ECMAScript / JavaScript言語自体は、UTF-16ではなくUCS-2に従って文字を公開します。

ソース


9
.split(/%(?:u[0-9A-F]{2})?[0-9A-F]{2}|./)代わりに使用してください。「%uXXXX」にエンコードする文字列のスニペットは失敗します。
ロブW

WebSocketフレームのサイズ計算に使用され、Chrome開発ツールと同じサイズの文字列フレームを提供します。
user85155 2015

2
s3にアップロードされたJavaScript文字列に使用され、s3はまったく同じサイズを表示します[(byteCount(s))/ 1024).toFixed(2)+ "KiB"]
user85155 2015年


41

Blobを使用して、文字列サイズをバイト単位で取得できます。

例:

console.info(
  new Blob(['😂']).size,                             // 4
  new Blob(['👍']).size,                             // 4
  new Blob(['😂👍']).size,                           // 8
  new Blob(['👍😂']).size,                           // 8
  new Blob(['I\'m a string']).size,                  // 12

  // from Premasagar correction of Lauri's answer for
  // strings containing lone characters in the surrogate pair range:
  // https://stackoverflow.com/a/39488643/6225838
  new Blob([String.fromCharCode(55555)]).size,       // 3
  new Blob([String.fromCharCode(55555, 57000)]).size // 4 (not 6)
);


2
ブロブを神に感謝します!これはおそらく、最近のブラウザで受け入れられている答えでしょう。
prasanthv

Node.jsにBlobをインポートする方法は?
アレクサンダーミルズ

4
ああ、Node.jsでは、たとえばBufferを使用しますBuffer.from('😂').length
AlexanderMills19年

19

unescapejs関数を使用してこの組み合わせを試してください。

const byteAmount = unescape(encodeURIComponent(yourString)).length

完全なエンコードプロセスの例:

const s  = "1 a ф № @ ®"; //length is 11
const s2 = encodeURIComponent(s); //length is 41
const s3 = unescape(s2); //length is 15 [1-1,a-1,ф-2,№-3,@-1,®-2]
const s4 = escape(s3); //length is 39
const s5 = decodeURIComponent(s4); //length is 11

4
unescapeJavaScript関数は廃止され、統一資源識別子(URI)をデコードするために使用すべきではありません。出典
Lauri Oherd 2012

@LauriOherdコメントが古いことは知っていますが、この回答でunescapeは、URIのデコードには使用されていません。%xxシーケンスを単一の文字に変換するために使用されます。encodeURIComponent文字列をUTF-8としてエンコードし、コードユニットを対応するASCII文字または%xxシーケンスとして表すと、呼び出しunescape(encodeURIComponent(...))により、元の文字列のUTF-8表現を含むバイナリ文字列が生成されます。.length正しく呼び出すと、UTF-8としてエンコードされた文字列のサイズがバイト単位で表示されます。
TS

そして、yes(unescapeは1999年から非推奨になっていますが、それでもすべてのブラウザで利用できます...-とはいえ、非推奨にするのには十分な理由があります。基本的に、それらを正しく使用する方法はありません(UTF8をen-/ decodeURIComponent)-と組み合わせてen- /デコードすることを除いて、または少なくとも(un)の他の便利なアプリケーションを知りませんescape)。そして今日エンコード/デコードUTF8(へのより良い代替手段があるTextEncoder、など)
TS

10

node.jsをターゲットにしている場合は、次を使用できることに注意してください Buffer.from(string).length

var str = "\u2620"; // => "☠"
str.length; // => 1 (character)
Buffer.from(str).length // => 3 (bytes)

7

UTF-8は、コードポイントごとに1〜4バイトを使用して文字をエンコードします。受け入れられた回答でCMSが指摘したように、JavaScriptは各文字を16ビット(2バイト)を使用して内部に格納します。

ループを介して文字列内の各文字を解析し、コードポイントごとに使用されるバイト数をカウントしてから、合計カウントに2を掛けると、そのUTF-8でエンコードされた文字列のJavaScriptのメモリ使用量がバイト単位になります。おそらくこのようなもの:

      getStringMemorySize = function( _string ) {
        "use strict";

        var codePoint
            , accum = 0
        ;

        for( var stringIndex = 0, endOfString = _string.length; stringIndex < endOfString; stringIndex++ ) {
            codePoint = _string.charCodeAt( stringIndex );

            if( codePoint < 0x100 ) {
                accum += 1;
                continue;
            }

            if( codePoint < 0x10000 ) {
                accum += 2;
                continue;
            }

            if( codePoint < 0x1000000 ) {
                accum += 3;
            } else {
                accum += 4;
            }
        }

        return accum * 2;
    }

例:

getStringMemorySize( 'I'    );     //  2
getStringMemorySize( '❤'    );     //  4
getStringMemorySize( '𠀰'   );     //  8
getStringMemorySize( 'I❤𠀰' );     // 14

7

これらは私が使用する3つの方法です:

  1. TextEncoder()

    (new TextEncoder().encode("myString")).length)

  2. ブロブ

    new Blob(["myString"]).size)

  3. バッファ

    Buffer.byteLength("myString", 'utf8'))


5

JavaScript文字列のサイズは

  • ES6より前:文字あたり2バイト
  • ES6以降:1文字あたり2バイト、または1文字あたり5バイト以上

ES6以前は
常に1文字あたり2バイト。仕様には「値は16ビットの符号なし整数でなければならない」と記載されているため、UTF-16は許可されていません。UTF-16文字列は3バイトまたは4バイトの文字を使用できるため、2バイトの要件に違反します。重要なことに、UTF-16は完全にはサポートされていませんが、標準では、使用される2バイト文字が有効なUTF-16文字である必要があります。つまり、ES6より前のJavaScript文字列は、UTF-16文字のサブセットをサポートします。

ES6以降は
1文字あたり2バイト、または1文字あたり5バイト以上。ES6(ECMAScript 6)がUnicodeコードポイントエスケープのサポートを追加するため、追加のサイズが機能しますます。Unicodeエスケープの使用は次のようになります:\ u {1D306}

実用的なメモ

  • これは、特定のエンジンの内部実装とは関係ありません。たとえば、一部のエンジンは完全なUTF-16サポートを備えたデータ構造とライブラリを使用しますが、外部で提供するものは完全なUTF-16サポートである必要はありません。また、エンジンは外部UTF-16サポートも提供する場合がありますが、そうすることは必須ではありません。

  • ES6の場合、Unicodeの最新バージョンには136,755文字しかなく、3バイトに簡単に収まるため、実際には文字の長さは5バイト(エスケープポイントの場合は2バイト+ Unicodeコードポイントの場合は3バイト)を超えることはありません。ただし、これは技術的には標準によって制限されていないため、原則として1文字でコードポイントに4バイト、合計6バイトを使用できます。

  • ここにあるバイトサイズを計算するためのコード例のほとんどは、ES6 Unicodeコードポイントエスケープを考慮していないようです。そのため、結果が正しくない場合があります。


1
サイズは、文字ごとに2バイトの場合だけでなぜ、不思議Buffer.from('test').lengthBuffer.byteLength('test')等しい4(ノード内)とnew Blob(['test']).sizeも4に等しいですか?
user10632 8719

ES6より前:UTF-16が許可されています:ECMA-262第3版(1999年から)を参照してください:1ページ目はUCS2またはUTF-16が許可されていると述べています。5ページ、文字列値の定義:「...各値は通常UTF-16テキストの単一の16ビット単位を表しますが...」。81ページの表は、一致する代理ペアを4つのUTF-8バイトとしてエンコードする方法を示しています。
TS

「文字ごと」-つまり、「ユーザーが認識した文字」(仕様簡単な説明)ごとに、16ビットコード単位をいくつでも指定できます。「コードポイント」ごとを意味する場合は、UTF-16の1つまたは2つの16ビットコードユニットにすることができます。(これは、2.5コード単位(することはできませんまたはあなたが5バイト)を取得する方法は?)
TS

javascript文字列の各要素(16ビットの符号なし整数値(「要素」))が実際に内部で2バイトで表されるかどうかは、標準では定義されていません。(そして、どのようになりますか?javascriptプログラムに提供されるインターフェースが標準に準拠している限り、すべてが意図したとおりに機能します。)たとえば、文字列にlatin1のみが含まれている場合、
TS

Unicodeコードポイントエスケープは、文字列の長さとは関係ありません。これは、ソースコードで文字列を表すための新しい方法にすぎません。('\u{1F600}'.length===2'\u{1F600}'==='\uD83D\uDE00''\u{1F600}'==='😀'
TS

3

JavaScript文字列の単一の要素は、単一のUTF-16コードユニットと見なされます。つまり、文字列文字は16ビット(1コード単位)で格納され、16ビットは2バイト(8ビット= 1バイト)に相当します。

ザ・ charCodeAt()メソッドを使用して、指定されたインデックスのUTF-16コードユニットを表す0〜65535の整数を返すことができます。

ザ・ codePointAt()、UTF-32などのUnicode文字のコードポイント値全体を返すために使用できます。

UTF-16文字を単一の16ビットコードユニットで表現できない場合、サロゲートペアを持つため、2つのコードユニット(2 x16ビット= 4バイト)を使用します。

さまざまなエンコーディングとそのコード範囲については、Unicodeエンコーディングを参照してください。


サロゲートについてあなたが言うことは、ECMAスクリプトの仕様に違反しているように思われます。上でコメントしたように、仕様では文字ごとに2バイトが必要であり、代理ペアを許可するとこれに違反します。
ホイットニーランド2017年

Javascript ES5エンジンは、内部的にUSC-2またはUTF-16を自由に使用できますが、実際に使用しているのは、サロゲートを備えた一種のUCS-2です。これは、サロゲートの半分を個別の文字、単一のUTF-16符号なし整数として公開できるためです。ソースコードで複数の16ビットコードユニットを表す必要があるUnicode文字を使用する場合は、サロゲートペアが使用されます。この動作は仕様に違反していません。第6章のソーステキストを参照してください:ecma-international.org/ecma-262/5.1
holmberd

2

Lauri Oherdからの回答は、実際に見られるほとんどの文字列でうまく機能しますが、文字列にサロゲートペアの範囲(0xD800〜0xDFFF)の単独の文字が含まれている場合は失敗します。例えば

byteCount(String.fromCharCode(55555))
// URIError: URI malformed

この長い関数はすべての文字列を処理する必要があります。

function bytes (str) {
  var bytes=0, len=str.length, codePoint, next, i;

  for (i=0; i < len; i++) {
    codePoint = str.charCodeAt(i);

    // Lone surrogates cannot be passed to encodeURI
    if (codePoint >= 0xD800 && codePoint < 0xE000) {
      if (codePoint < 0xDC00 && i + 1 < len) {
        next = str.charCodeAt(i + 1);

        if (next >= 0xDC00 && next < 0xE000) {
          bytes += 4;
          i++;
          continue;
        }
      }
    }

    bytes += (codePoint < 0x80 ? 1 : (codePoint < 0x800 ? 2 : 3));
  }

  return bytes;
}

例えば

bytes(String.fromCharCode(55555))
// 3

サロゲートペアを含む文字列のサイズを正しく計算します。

bytes(String.fromCharCode(55555, 57000))
// 4 (not 6)

結果は、Nodeの組み込み関数と比較できますBuffer.byteLength

Buffer.byteLength(String.fromCharCode(55555), 'utf8')
// 3

Buffer.byteLength(String.fromCharCode(55555, 57000), 'utf8')
// 4 (not 6)

1

私はV8エンジンの組み込みバージョンで作業しています。私は単一の文字列をテストしました。各ステップを1000文字押します。UTF-8。

1バイト(8ビット、ANSI)文字「A」(16進数:41)を使用した最初のテスト。2バイト文字(16ビット)「Ω」(16進数:CE A9)を使用した2番目のテストと3バイト文字(24ビット)「☺」(16進数:E2 98 BA)を使用した3番目のテスト。

3つのケースすべてで、デバイスは888 000文字でメモリから出力し、約 RAMに26348kb。

結果:文字は動的に保存されません。そして、16ビットだけではありません。-わかりました。おそらく私の場合のみです(組み込み128 MB RAMデバイス、V8エンジンC ++ / QT)-文字エンコードは、JavaScriptエンジンのRAMのサイズとは関係ありません。たとえば、encodingURIなどは、高レベルのデータ送信と保存にのみ役立ちます。

埋め込まれているかどうかにかかわらず、文字は16ビットで格納されるだけではありません。残念ながら、Javascriptが低レベルの領域で何をするのか、100%答えはありません。ところで。文字「A」の配列を使用して同じテストを行いました(上記の最初のテスト)。ステップごとに1000アイテムをプッシュしました。(まったく同じテスト。文字列を配列に置き換えただけです)そして、システムは10 416 KBを使用し、配列の長さを1 337 000にした後、メモリを使い果たしました(必要)。したがって、javascriptエンジンは単純に制限されていません。それはちょっと複雑です。


0

あなたはこれを試すことができます:

  var b = str.match(/[^\x00-\xff]/g);
  return (str.length + (!b ? 0: b.length)); 

それは私のために働いた。


1
確かにこれはすべての文字が最大2バイトであることを前提としていますか?3バイトまたは4バイトの文字(UTF-8で可能)がある場合、この関数はそれらを2バイト文字としてのみカウントしますか?
アダムバーリー2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.