JavaScript中的string长度(字节)

在我的JavaScript代码中,我需要用这种格式编写一个消息给服务器:

<size in bytes>CRLF <data>CRLF 

例:

 3 foo 

数据可能包含unicode字符。 我需要把它们作为UTF-8发送。

我正在寻找最具有跨浏览器的方式来计算JavaScript中string的长度。

我已经试过这个来组成我的有效载荷:

 return unescape(encodeURIComponent(str)).length + "\n" + str + "\n" 

但是,对于旧版本的浏览器(或者UTF-16浏览器中的string),它并没有给出准确的结果。

任何线索?

更新:

示例:string的长度(以字节为ЭЭХ! Naïve? ЭЭХ! Naïve? 在UTF-8中是15字节,而有些浏览器则报告23字节。

原生JavaScript中没有办法做到这一点。

如果你知道字符编码,你可以自己计算一下。

encodeURIComponent采用UTF-8作为字符编码,所以如果你需要这种编码,你可以做,

 function lengthInUtf8Bytes(str) { // Matches only the 10.. bytes that are non-initial characters in a multi-byte sequence. var m = encodeURIComponent(str).match(/%[89ABab]/g); return str.length + (m ? m.length : 0); } 

这应该是因为UTF-8编码多字节序列的方式。 第一个编码的字节总是以单个字节序列的高位为零或者第一个hex数字为C,D,E或F的字节开始。第二个和随后的字节是前两位为10这些是你想用UTF-8计算的额外字节。

维基百科中的表格使得它更清晰

 Bits Last code point Byte 1 Byte 2 Byte 3 7 U+007F 0xxxxxxx 11 U+07FF 110xxxxx 10xxxxxx 16 U+FFFF 1110xxxx 10xxxxxx 10xxxxxx ... 

如果您需要了解页面编码,则可以使用以下技巧:

 function lengthInPageEncoding(s) { var a = document.createElement('A'); a.href = '#' + s; var sEncoded = a.href; sEncoded = sEncoded.substring(sEncoded.indexOf('#') + 1); var m = sEncoded.match(/%[0-9a-f]{2}/g); return sEncoded.length - (m ? m.length * 2 : 0); } 

这是一个更快的版本,它不使用正则expression式,也不encodeURIComponent:

 function byteLength(str) { // returns the byte length of an utf8 string var s = str.length; for (var i=str.length-1; i>=0; i--) { var code = str.charCodeAt(i); if (code > 0x7f && code <= 0x7ff) s++; else if (code > 0x7ff && code <= 0xffff) s+=2; if (code >= 0xDC00 && code <= 0xDFFF) i--; //trail surrogate } return s; } 

这是一个性能比较 。

它只计算由charCodeAt返回的每个unicode代码点的UTF8长度(基于维基百科的UTF8描述和UTF16代理字符)。

它遵循RFC3629 (UTF-8字符长度最多为4个字节)。

几年过去了,现在你可以自己做

 (new TextEncoder('utf-8').encode('foo')).length 

请注意,IE(或Edge)不支持它(你可以使用一个polyfill )。

MDN文档

标准规格

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

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

资源

对于简单的UTF-8编码,比TextEncoder稍好一点的兼容性,Blob就能做到这一点。 虽然不会在很老的浏览器中工作。

 new Blob(["😀"]).size; // -> 4 

其实我找出了什么是错的 对于工作的代码页<head>应该有这个标签:

 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 

或者,如注释中所build议的,如果服务器发送HTTP Content-Encoding标头,它也应该工作。

然后来自不同浏览器的结果是一致的。

这里是一个例子:

 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>mini string length test</title> </head> <body> <script type="text/javascript"> document.write('<div style="font-size:100px">' + (unescape(encodeURIComponent("ЭЭХ! Naïve?")).length) + '</div>' ); </script> </body> </html> 

注:我怀疑指定任何 (准确)编码将解决编码问题。 我只需要UTF-8就是一个巧合。

你可以试试这个:

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

它适用于我。

这是一个独立而有效的方法来计算一个string的UTF-8字节。

 //count UTF-8 bytes of a string function byteLengthOf(s){ //assuming the String is UCS-2(aka UTF-16) encoded var n=0; for(var i=0,l=s.length; i<l; i++){ var hi=s.charCodeAt(i); if(hi<0x0080){ //[0x0000, 0x007F] n+=1; }else if(hi<0x0800){ //[0x0080, 0x07FF] n+=2; }else if(hi<0xD800){ //[0x0800, 0xD7FF] n+=3; }else if(hi<0xDC00){ //[0xD800, 0xDBFF] var lo=s.charCodeAt(++i); if(i<l&&lo>=0xDC00&&lo<=0xDFFF){ //followed by [0xDC00, 0xDFFF] n+=4; }else{ throw new Error("UCS-2 String malformed"); } }else if(hi<0xE000){ //[0xDC00, 0xDFFF] throw new Error("UCS-2 String malformed"); }else{ //[0xE000, 0xFFFF] n+=3; } } return n; } var s="\u0000\u007F\u07FF\uD7FF\uDBFF\uDFFF\uFFFF"; console.log("expect byteLengthOf(s) to be 14, actually it is %s.",byteLengthOf(s)); 

另一种使用Buffer非常简单的方法(仅用于NodeJS):

 Buffer.from(string).length 

这将适用于BMP和SIP / SMP字符。

  String.prototype.lengthInUtf8 = function() { var asciiLength = this.match(/[\u0000-\u007f]/g) ? this.match(/[\u0000-\u007f]/g).length : 0; var multiByteLength = encodeURI(this.replace(/[\u0000-\u007f]/g)).match(/%/g) ? encodeURI(this.replace(/[\u0000-\u007f]/g, '')).match(/%/g).length : 0; return asciiLength + multiByteLength; } 'test'.lengthInUtf8(); // returns 4 '\u{2f894}'.lengthInUtf8(); // returns 4 'سلام علیکم'.lengthInUtf8(); // returns 19, each Arabic/Persian alphabet character takes 2 bytes. '你好,JavaScript 世界'.lengthInUtf8(); // returns 26, each Chinese character/punctuation takes 3 bytes.