Ale*_*ysh 85 javascript unicode
在我的JavaScript代码中,我需要以这种格式向服务器撰写消息:
<size in bytes>CRLF
<data>CRLF
Run Code Online (Sandbox Code Playgroud)
例:
3
foo
Run Code Online (Sandbox Code Playgroud)
数据可能包含unicode字符.我需要将它们作为UTF-8发送.
我正在寻找最流行的浏览器方式来计算JavaScript中字符串的长度(以字节为单位).
我试过这个来组成我的有效载荷:
return unescape(encodeURIComponent(str)).length + "\n" + str + "\n"
Run Code Online (Sandbox Code Playgroud)
但它没有给我准确的结果旧浏览器(或者,这些浏览器中的字符串可能是UTF-16?).
有线索吗?
更新:
示例:???! Naïve?UTF-8中字符串的长度(以字节为单位)为15个字节,但某些浏览器报告的是23个字节.
Ric*_*lli 90
多年过去了,现在你可以做到这一点
(new TextEncoder().encode('foo')).length
Run Code Online (Sandbox Code Playgroud)
请注意,IE(或Edge)尚不支持它(您可以使用polyfill).
Mik*_*uel 81
在本机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);
}
Run Code Online (Sandbox Code Playgroud)
这应该有效,因为UTF-8编码多字节序列的方式.对于单字节序列,第一个编码字节始终以高位0开始,或者以第一个十六进制数字为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
...
Run Code Online (Sandbox Code Playgroud)
如果你需要了解页面编码,你可以使用这个技巧:
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);
}
Run Code Online (Sandbox Code Playgroud)
lov*_*soa 60
这是一个更快的版本,它不使用正则表达式,也不使用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;
}
Run Code Online (Sandbox Code Playgroud)
这是性能比较.
它只计算charCodeAt返回的每个unicode代码点的UTF8长度(基于维基百科对UTF8和UTF16代理字符的描述).
它遵循RFC3629(其中UTF-8字符最多为4个字节长).
sim*_*map 40
对于简单的UTF-8编码,兼容性稍好一些TextEncoder,Blob可以解决问题.但是在旧的浏览器中不起作用.
new Blob([""]).size; // -> 4
Run Code Online (Sandbox Code Playgroud)
Lau*_*erd 29
此函数将返回传递给它的任何UTF-8字符串的字节大小.
function byteCount(s) {
return encodeURI(s).split(/%..|./).length - 1;
}
Run Code Online (Sandbox Code Playgroud)
Ivá*_*rez 15
使用另一种非常简单的方法Buffer(仅适用于NodeJS):
Buffer.from(string).length
Run Code Online (Sandbox Code Playgroud)
All*_*sso 11
我比较了 Firefox 中建议的一些方法的速度。
\n我使用的字符串包含以下字符:\n\xc5\x93\xc2\xb4\xc2\xae\xe2\x80\xa0\xc2\xa5\xc2\xa8\xcb\x86\xc3\xb8\xcf\x80\ xc2\xac\xcb\x9a\xe2\x88\x86\xcb\x99\xc2\xa9\xc6\x92\xe2\x88\x82\xc3\x9f\xc3\xa5\xce\xa9\xe2\x89\x88\ xc3\xa7\xe2\x88\x9a\xe2\x88\xab\xcb\x9c\xc2\xb5\xe2\x89\xa4
\n所有结果均为 3 次运行的平均值。时间以毫秒为单位。请注意,所有 URIEncoding 方法的行为都相似并且具有极端的结果,因此我只包含一种。
\n虽然根据字符串的大小存在一些波动,但 charCode 方法(lovasoa 和 fuweichin)的性能相似且总体速度最快,其中 fuweichin 的 charCode 方法最快。Blob 和 TextEncoder 方法的执行方式类似。一般来说,charCode 方法比 Blob 和 TextEncoder 方法快约 75%。URIEncoding方法基本上是不可接受的。
\n这是我得到的结果:
\n大小 6.4 * 10^6 字节:
\nLauri Oherd \xe2\x80\x93 URIEncoding: 6400000 et: 796\nlovasoa \xe2\x80\x93 charCode: 6400000 et: 15\nfuweichin \xe2\x80\x93 charCode2: 6400000 et: 16\nsimap \xe2\x80\x93 Blob: 6400000 et: 26\nRiccardo Galli \xe2\x80\x93 TextEncoder: 6400000 et: 23\nRun Code Online (Sandbox Code Playgroud)\n大小 19.2 * 10^6 字节:\nBlob 在这里做了一些奇怪的事情。
\nLauri Oherd \xe2\x80\x93 URIEncoding: 19200000 et: 2322\nlovasoa \xe2\x80\x93 charCode: 19200000 et: 42\nfuweichin \xe2\x80\x93 charCode2: 19200000 et: 45\nsimap \xe2\x80\x93 Blob: 19200000 et: 169\nRiccardo Galli \xe2\x80\x93 TextEncoder: 19200000 et: 70\nRun Code Online (Sandbox Code Playgroud)\n大小 64 * 10^6 字节:
\nLauri Oherd \xe2\x80\x93 URIEncoding: 64000000 et: 12565\nlovasoa \xe2\x80\x93 charCode: 64000000 et: 138\nfuweichin \xe2\x80\x93 charCode2: 64000000 et: 133\nsimap \xe2\x80\x93 Blob: 64000000 et: 231\nRiccardo Galli \xe2\x80\x93 TextEncoder: 64000000 et: 211\nRun Code Online (Sandbox Code Playgroud)\n大小 192 * 10^6 字节:\nURIEncoding 方法此时会冻结浏览器。
\nlovasoa \xe2\x80\x93 charCode: 192000000 et: 754\nfuweichin \xe2\x80\x93 charCode2: 192000000 et: 480\nsimap \xe2\x80\x93 Blob: 192000000 et: 701\nRiccardo Galli \xe2\x80\x93 TextEncoder: 192000000 et: 654\nRun Code Online (Sandbox Code Playgroud)\n大小 640 * 10^6 字节:
\nlovasoa \xe2\x80\x93 charCode: 640000000 et: 2417\nfuweichin \xe2\x80\x93 charCode2: 640000000 et: 1602\nsimap \xe2\x80\x93 Blob: 640000000 et: 2492\nRiccardo Galli \xe2\x80\x93 TextEncoder: 640000000 et: 2338\nRun Code Online (Sandbox Code Playgroud)\n大小 1280 * 10^6 字节:\nBlob 和 TextEncoder 方法在这里开始遇到困难。
\nlovasoa \xe2\x80\x93 charCode: 1280000000 et: 4780\nfuweichin \xe2\x80\x93 charCode2: 1280000000 et: 3177\nsimap \xe2\x80\x93 Blob: 1280000000 et: 6588\nRiccardo Galli \xe2\x80\x93 TextEncoder: 1280000000 et: 5074\nRun Code Online (Sandbox Code Playgroud)\n大小 1920 * 10^6 字节:
\nlovasoa \xe2\x80\x93 charCode: 1920000000 et: 7465\nfuweichin \xe2\x80\x93 charCode2: 1920000000 et: 4968\nJavaScript error: file:///Users/xxx/Desktop/test.html, line 74: NS_ERROR_OUT_OF_MEMORY:\nRun Code Online (Sandbox Code Playgroud)\n这是代码:
\nLauri Oherd \xe2\x80\x93 URIEncoding: 6400000 et: 796\nlovasoa \xe2\x80\x93 charCode: 6400000 et: 15\nfuweichin \xe2\x80\x93 charCode2: 6400000 et: 16\nsimap \xe2\x80\x93 Blob: 6400000 et: 26\nRiccardo Galli \xe2\x80\x93 TextEncoder: 6400000 et: 23\nRun Code Online (Sandbox Code Playgroud)\r\n我花了一段时间才找到React Native的解决方案,所以我把它放在这里:
首先安装buffer软件包:
npm install --save buffer
Run Code Online (Sandbox Code Playgroud)
然后使用节点方法:
const { Buffer } = require('buffer');
const length = Buffer.byteLength(string, 'utf-8');
Run Code Online (Sandbox Code Playgroud)
事实上,我想出了什么问题。为了使代码工作,页面<head>应该有这个标签:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
Run Code Online (Sandbox Code Playgroud)
或者,正如评论中所建议的,如果服务器发送 HTTPContent-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>
Run Code Online (Sandbox Code Playgroud)
注意:我怀疑指定任何(准确的)编码都会解决编码问题。我需要UTF-8只是一个巧合。
在 NodeJS 中,Buffer.byteLength有一个专门用于此目的的方法:
let strLengthInBytes = Buffer.byteLength(str); // str is UTF-8
Run Code Online (Sandbox Code Playgroud)
请注意,默认情况下,该方法假定字符串采用 UTF-8 编码。如果需要不同的编码,请将其作为第二个参数传递。
| 归档时间: |
|
| 查看次数: |
95468 次 |
| 最近记录: |