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.