一个 JavaScript 字符串有多少字节?

我有一个 javascript 字符串,当从服务器以 UTF-8发送时,它大约是500K。如何用 JavaScript 判断它的大小?

我知道 JavaScript 使用 UCS-2,所以这意味着每个字符2字节。然而,它是否依赖于 JavaScript 实现?或者页面编码或者内容类型?

157196 次浏览

String值与实现无关,根据 ECMA-262第3版规范,每个字符代表一个 单个16位 UTF-16文本单元:

4.3.16字符串值

字符串值是 String 类型的成员,并且是 零或零的有限序列 更多的16位无符号整数值。

注意虽然每个值通常 表示单个16位的 UTF-16文本,语言不通 设置任何限制或要求 除了它们是 16位无符号整数。

尝试使用 无法逃脱 js 函数结合使用这个函数:

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

该函数将返回传递给它的任何 UTF-8字符串的字节大小。

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

来源

JavaScript 引擎可以在内部免费使用 UCS-2或 UTF-16。我所知道的大多数引擎都使用 UTF-16,但不管它们做出什么选择,它只是一个不会影响语言特性的实现细节。

然而,ECMAScript/JavaScript 语言本身根据 UCS-2而不是 UTF-16公开字符。

来源

你可以试试这个:

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

这招对我很管用。

如果您正在使用 node.js,那么使用 缓冲器有一个更简单的解决方案:

function getBinarySize(string) {
return Buffer.byteLength(string, 'utf8');
}

这里有一个 npm lib: https://www.npmjs.org/package/utf8-binary-cutter(忠实地来自您的)

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

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。

首先使用单字节(8位,ANSI)字符“ A”(十六进制: 41)进行测试。 第二次测试的两个字节字符(16位)“ Ω”(十六进制代码: CEA9)和 第三个测试与三个字节的字符(24位)“兴”(十六进制: E298 BA)。

在这三种情况下,设备打印出的内存都是 888000个字符,并在 RAM 中使用约26348kb。

结果: 字符不是动态存储的。而且不是只有16位。- 好吧,也许只是为了我的案例(嵌入式128MB 内存设备,v8引擎 C + +/QT)-这个字符编码与 javascript 引擎的内存大小无关。例如,encoding/URI 等仅适用于高级数据传输和存储。

不管是否嵌入,事实上这些字符不仅仅存储在16位中。 不幸的是,我没有100% 的答案,Javascript 在底层做什么。 顺便说一下,我已经用一个字符“ A”的数组测试了相同的内容(上面的第一个测试)。 每步推送1000个项目。(完全相同的测试。只是替换字符串到数组)和系统带出内存(需要)后10416 KB 的使用和数组长度为1337000。 因此,javascript 引擎不是简单的受限制的,而是一种更加复杂的。

JavaScriptString 中的单个元素被认为是单个 UTF-16代码单元。也就是说,字符串字符存储在16位(1个代码单元)中,16位等于2字节(8位 = 1字节)。

charCodeAt()方法可用于返回一个介于0和65535之间的整数,该整数表示给定索引处的 UTF-16代码单元。

codePointAt()可以用来返回 Unicode 字符的整个代码点值,例如 UTF-32。

当 UTF-16字符不能在单个16位代码单元中表示时,它将有一个代理对,因此使用两个代码单元(2 x 16位 = 4字节)

有关不同的编码及其代码范围,请参见 Unicode 编码

注意,如果你的目标是 node.js,你可以使用 Buffer.from(string).length:

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

JavaScript 字符串的大小为

  • 前 ES6 : 每个字符2字节
  • ES6 及更高版本: 每个字符2字节, 或每个字符5个或更多字节

ES6之前
每个字符总是2字节。UTF-16是不允许的,因为规范说明“值必须是16位无符号整数”。由于 UTF-16字符串可以使用3或4个字节的字符,它将违反2字节的要求。至关重要的是,虽然不能完全支持 UTF-16,但标准确实要求使用的两个字节字符是有效的 UTF-16字符。换句话说,Pre-ES6 JavaScript 字符串支持 UTF-16字符的一个子集。

ES6以及更高版本
每个字符2个字节,或者每个字符5个或更多字节。由于 ES6(ECMAScript 6)增加了对 Unicode字符逃脱的支持,因此需要使用额外的大小。使用 Unicode 转义符如下所示: u {1D306}

实用注释

  • 这与特定引擎的内部实现无关 例如,一些引擎使用数据结构和库 UTF-16的支持,但他们提供的外部不一定是 完全支持 UTF-16。引擎也可以提供外部 UTF-16 支持,但没有这样做的授权。

  • 对于 ES6来说,实际上字符数永远不会超过5 长(转义点为2字节,Unicode 为3字节) 编码点) ,因为最新版本的 Unicode 只有136,755 可能的字符,这很容易放入3个字节。然而,这是 技术上不受标准的限制,所以在原则上 字符可以使用比如4个字节作为代码点和6个字节 总数。

  • 这里大多数用于计算字节大小的代码示例似乎没有考虑到 ES6的 Unicode字符转义,因此在某些情况下,结果可能是不正确的。

可以使用 团团获取字符串大小(以字节为单位)。

例子:

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)
);

以下是我使用的三种方法:

  1. TextEncoder
new TextEncoder().encode("myString").length
  1. Blob
new Blob(["myString"]).size
  1. Buffer
Buffer.byteLength("myString", 'utf8')

团团接口的 size 属性返回 Blob 或 File 的大小(以字节为单位)。

const getStringSize = (s) => new Blob([s]).size;