从服务器以UTF-8发送时,我有一个大约500K的JavaScript字符串。如何用JavaScript判断其大小?
我知道JavaScript使用UCS-2,因此每个字符2个字节。但是,这取决于JavaScript实现吗?还是页面编码或内容类型?
从服务器以UTF-8发送时,我有一个大约500K的JavaScript字符串。如何用JavaScript判断其大小?
我知道JavaScript使用UCS-2,因此每个字符2个字节。但是,这取决于JavaScript实现吗?还是页面编码或内容类型?
Answers:
String
值不依赖于实现,根据ECMA-262第三版规范,每个字符代表UTF-16文本的单个16位单元:
4.3.16字符串值
字符串值是String类型的成员,并且是零个或多个16位无符号整数值的有限有序序列。
注意尽管每个值通常代表UTF-16文本的单个16位单元,但是语言对这些值没有任何限制或要求,只是它们是16位无符号整数。
.split(/%(?:u[0-9A-F]{2})?[0-9A-F]{2}|./)
代替。您的代码段无法编码为“%uXXXX”的字符串。
如果您使用的是node.js,那么有一个使用缓冲区的简单解决方案:
function getBinarySize(string) {
return Buffer.byteLength(string, 'utf8');
}
有一个npm lib:https : //www.npmjs.org/package/utf8-binary-cutter(忠实地来自您)
您可以使用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
使用unescape 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
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之前
始终每个字符2个字节。不允许使用UTF-16,因为规范指出“值必须是16位无符号整数”。由于UTF-16字符串可以使用3个或4个字节的字符,因此将违反2个字节的要求。至关重要的是,虽然不能完全支持UTF-16,但该标准确实要求使用的两个字节字符为有效的UTF-16字符。换句话说,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代码点转义,因此在某些情况下结果可能不正确。
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()
方法可用于返回0到65535之间的整数,该整数表示给定索引处的UTF-16代码单元。
的 codePointAt()
可用于为Unicode字符返回整个码点值,例如UTF-32。
如果无法在单个16位代码单元中表示UTF-16字符,它将具有一个代理对,因此使用两个代码单元(2 x 16位= 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。
第一次测试使用单字节(8位,ANSI)字符“ A”(十六进制:41)。第二个测试使用两个字节字符(16位)“Ω”(十六进制:CE A9),第三个测试使用三个字节字符(24位)“☺”(十六进制:E2 98 BA)。
在这三种情况下,设备都将以888 000个字符打印出内存,并且使用ca。RAM中的26348 kb
结果:字符不是动态存储的。而且不是只有16位。-好的,也许仅就我而言(嵌入式128 MB RAM设备,V8引擎C ++ / QT)-字符编码与javascript引擎的ram大小无关。例如encodingURI等仅对高级数据传输和存储有用。
是否嵌入,事实是字符不仅以16bit存储。不幸的是,我没有100%的答案,即Javascript在低级别区域的作用。顺便说一句。我已经用字符“ A”的数组测试了相同的(上面的第一个测试)。每步推送1000个项目。(完全相同的测试。只是将字符串替换为数组),使用10 416 KB且数组长度为1 337 000后,系统导致内存不足(需要)(数组)。因此,javascript引擎不是简单的限制。这有点复杂。