UTF-8でサーバーから送信されたときに約500KのJavaScript文字列があります。JavaScriptでそのサイズを確認するにはどうすればよいですか?
JavaScriptがUCS-2を使用していることは知っています。つまり、1文字あたり2バイトを意味します。しかし、それはJavaScriptの実装に依存しますか?またはページエンコーディングまたは多分コンテンツタイプで?
UTF-8でサーバーから送信されたときに約500KのJavaScript文字列があります。JavaScriptでそのサイズを確認するにはどうすればよいですか?
JavaScriptがUCS-2を使用していることは知っています。つまり、1文字あたり2バイトを意味します。しかし、それはJavaScriptの実装に依存しますか?またはページエンコーディングまたは多分コンテンツタイプで?
回答:
String
ECMA-262 3rd Edition仕様によると、値は実装に依存しません。各文字は、UTF-16テキストの単一の16ビット単位を表します。
4.3.16文字列値
文字列値はString型のメンバーであり、0個以上の16ビット符号なし整数値の有限順序シーケンスです。
注各値は通常、UTF-16テキストの単一の16ビット単位を表しますが、言語は、16ビットの符号なし整数であることを除いて、値に制限や要件を課しません。
.split(/%(?:u[0-9A-F]{2})?[0-9A-F]{2}|./)
代わりに使用してください。「%uXXXX」にエンコードする文字列のスニペットは失敗します。
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)
);
Buffer.from('😂').length
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
unescape
JavaScript関数は廃止され、統一資源識別子(URI)をデコードするために使用すべきではありません。出典
un
)escape
は1999年から非推奨になっていますが、それでもすべてのブラウザで利用できます...-とはいえ、非推奨にするのには十分な理由があります。基本的に、それらを正しく使用する方法はありません(UTF8をen
-/ decodeURI
(Component
)-と組み合わせてen- /デコードすることを除いて、または少なくとも(un
)の他の便利なアプリケーションを知りませんescape
)。そして今日エンコード/デコードUTF8(へのより良い代替手段があるTextEncoder
、など)
node.jsをターゲットにしている場合は、次を使用できることに注意してください Buffer.from(string).length
:
var str = "\u2620"; // => "☠"
str.length; // => 1 (character)
Buffer.from(str).length // => 3 (bytes)
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
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コードポイントエスケープを考慮していないようです。そのため、結果が正しくない場合があります。
Buffer.from('test').length
とBuffer.byteLength('test')
等しい4(ノード内)とnew Blob(['test']).size
も4に等しいですか?
'\u{1F600}'.length===2
、'\u{1F600}'==='\uD83D\uDE00'
、'\u{1F600}'==='😀'
)
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エンコーディングを参照してください。
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)
私は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エンジンは単純に制限されていません。それはちょっと複雑です。
あなたはこれを試すことができます:
var b = str.match(/[^\x00-\xff]/g);
return (str.length + (!b ? 0: b.length));
それは私のために働いた。