.charCodeAt
函数返回字符的Unicode编码。但是我想得到字节数组而不是字符编码。我知道,如果字符编码超过127,则该字符存储在两个或多个字节中。
var arr=[];
for(var i=0; i<str.length; i++) {
arr.push(str.charCodeAt(i))
}
.charCodeAt
函数返回字符的Unicode编码。但是我想得到字节数组而不是字符编码。我知道,如果字符编码超过127,则该字符存储在两个或多个字节中。
var arr=[];
for(var i=0; i<str.length; i++) {
arr.push(str.charCodeAt(i))
}
Unicode在UTF-8中的编码逻辑基本如下:
这里是我之前编写的一个函数,用于将JavaScript UTF-16字符串编码为UTF-8:
function toUTF8Array(str) {
var utf8 = [];
for (var i=0; i < str.length; i++) {
var charcode = str.charCodeAt(i);
if (charcode < 0x80) utf8.push(charcode);
else if (charcode < 0x800) {
utf8.push(0xc0 | (charcode >> 6),
0x80 | (charcode & 0x3f));
}
else if (charcode < 0xd800 || charcode >= 0xe000) {
utf8.push(0xe0 | (charcode >> 12),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f));
}
// surrogate pair
else {
i++;
// UTF-16 encodes 0x10000-0x10FFFF by
// subtracting 0x10000 and splitting the
// 20 bits of 0x0-0xFFFFF into two halves
charcode = 0x10000 + (((charcode & 0x3ff)<<10)
| (str.charCodeAt(i) & 0x3ff));
utf8.push(0xf0 | (charcode >>18),
0x80 | ((charcode>>12) & 0x3f),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f));
}
}
return utf8;
}
String
。encodeURIComponent()
,它将输出UTF-8字节的URL编码,并使用unescape
,如在ecmanaut上提到的那样。var utf8 = unescape(encodeURIComponent(str));
var arr = [];
for (var i = 0; i < utf8.length; i++) {
arr.push(utf8.charCodeAt(i));
}
使用编码 API,你可以轻松进行UTF-8的编码和解码(使用类型化数组):
var encoded = new TextEncoder().encode("Γεια σου κόσμε");
var decoded = new TextDecoder("utf-8").decode(encoded);
console.log(encoded, decoded);
浏览器支持还不错,并且有一个polyfill可以在IE11和旧版本的Edge中使用。
虽然TextEncoder
只能编码为UTF-8,但TextDecoder
支持其他编码方式。我用它来解码日语文本(Shift-JIS)的方法如下:
// Shift-JIS encoded text; must be a byte array due to values 129 and 130.
var arr = [130, 108, 130, 102, 130, 80, 129, 64, 130, 102, 130, 96, 130, 108, 130, 100,
129, 64, 130, 99, 130, 96, 130, 115, 130, 96, 129, 124, 130, 79, 130, 80];
// Convert to byte array
var data = new Uint8Array(arr);
// Decode with TextDecoder
var decoded = new TextDecoder("shift-jis").decode(data.buffer);
console.log(decoded);
.decode()
在字符串上不起作用,因此如果您尝试解码一个恰好处于 utf8 格式的字节字符串(在某些环境中可能会发生),则无法使用。 - Dylan Nicholson谷歌闭包库有将UTF-8转换为字节数组和反向转换的函数。如果您不想使用整个库,可以从这里复制函数。为了完整起见,将字符串转换为UTF-8字节数组的代码如下:
goog.crypt.stringToUtf8ByteArray = function(str) {
// TODO(user): Use native implementations if/when available
var out = [], p = 0;
for (var i = 0; i < str.length; i++) {
var c = str.charCodeAt(i);
if (c < 128) {
out[p++] = c;
} else if (c < 2048) {
out[p++] = (c >> 6) | 192;
out[p++] = (c & 63) | 128;
} else if (
((c & 0xFC00) == 0xD800) && (i + 1) < str.length &&
((str.charCodeAt(i + 1) & 0xFC00) == 0xDC00)) {
// Surrogate Pair
c = 0x10000 + ((c & 0x03FF) << 10) + (str.charCodeAt(++i) & 0x03FF);
out[p++] = (c >> 18) | 240;
out[p++] = ((c >> 12) & 63) | 128;
out[p++] = ((c >> 6) & 63) | 128;
out[p++] = (c & 63) | 128;
} else {
out[p++] = (c >> 12) | 224;
out[p++] = ((c >> 6) & 63) | 128;
out[p++] = (c & 63) | 128;
}
}
return out;
};
.readAsArrayBuffer()
函数转换为ArrayBuffer示例:
// Create a Blob with an Euro-char (U+20AC)
var b = new Blob(['€']);
var fr = new FileReader();
fr.onload = function() {
ua = new Uint8Array(fr.result);
// This will log "3|226|130|172"
// E2 82 AC
// In UTF-16, it would be only 2 bytes long
console.log(
fr.result.byteLength + '|' +
ua[0] + '|' +
ua[1] + '|' +
ua[2] + ''
);
};
fr.readAsArrayBuffer(b);
在JSFiddle上尝试一下。我还没有对此进行基准测试,但我可以想象这对于大型DOM字符串作为输入是很有效的。
将字符串保存到 blob 中,然后调用 readAsArrayBuffer()。然后 onload 事件会返回一个数组缓冲区,该缓冲区可以转换为 Uint8Array。不幸的是,此调用是异步的。
以下这个小函数将会帮助您:
function stringToBytes(str)
{
let reader = new FileReader();
let done = () => {};
reader.onload = event =>
{
done(new Uint8Array(event.target.result), str);
};
reader.readAsArrayBuffer(new Blob([str], { type: "application/octet-stream" }));
return { done: callback => { done = callback; } };
}
这样调用:
stringToBytes("\u{1f4a9}").done(bytes =>
{
console.log(bytes);
});
输出: [240, 159, 146, 169]
解释:
JavaScript使用UTF-16和代理对来存储内存中的Unicode字符。为了将Unicode字符保存在原始二进制字节流中,需要进行编码。
通常情况下,大多数情况下使用UTF-8进行编码。如果不使用编码,则只能保存ASCII字符,最高到0x7f。
FileReader.readAsArrayBuffer()使用UTF-8编码。
byte
类型,因此我们可以将字节数组表示为数字数组,其中每个数字表示一个字节,因此其整数值介于0和255之间(包括0和255)。function toUtf8(str) {
var value = [];
var destIndex = 0;
for (var index = 0; index < str.length; index++) {
var code = str.charCodeAt(index);
if (code <= 0x7F) {
value[destIndex++] = code;
} else if (code <= 0x7FF) {
value[destIndex++] = ((code >> 6 ) & 0x1F) | 0xC0;
value[destIndex++] = ((code >> 0 ) & 0x3F) | 0x80;
} else if (code <= 0xFFFF) {
value[destIndex++] = ((code >> 12) & 0x0F) | 0xE0;
value[destIndex++] = ((code >> 6 ) & 0x3F) | 0x80;
value[destIndex++] = ((code >> 0 ) & 0x3F) | 0x80;
} else if (code <= 0x1FFFFF) {
value[destIndex++] = ((code >> 18) & 0x07) | 0xF0;
value[destIndex++] = ((code >> 12) & 0x3F) | 0x80;
value[destIndex++] = ((code >> 6 ) & 0x3F) | 0x80;
value[destIndex++] = ((code >> 0 ) & 0x3F) | 0x80;
} else if (code <= 0x03FFFFFF) {
value[destIndex++] = ((code >> 24) & 0x03) | 0xF0;
value[destIndex++] = ((code >> 18) & 0x3F) | 0x80;
value[destIndex++] = ((code >> 12) & 0x3F) | 0x80;
value[destIndex++] = ((code >> 6 ) & 0x3F) | 0x80;
value[destIndex++] = ((code >> 0 ) & 0x3F) | 0x80;
} else if (code <= 0x7FFFFFFF) {
value[destIndex++] = ((code >> 30) & 0x01) | 0xFC;
value[destIndex++] = ((code >> 24) & 0x3F) | 0x80;
value[destIndex++] = ((code >> 18) & 0x3F) | 0x80;
value[destIndex++] = ((code >> 12) & 0x3F) | 0x80;
value[destIndex++] = ((code >> 6 ) & 0x3F) | 0x80;
value[destIndex++] = ((code >> 0 ) & 0x3F) | 0x80;
} else {
throw new Error("Unsupported Unicode character \""
+ str.charAt(index) + "\" with code " + code + " (binary: "
+ toBinary(code) + ") at index " + index
+ ". Cannot represent it as UTF-8 byte sequence.");
}
}
return value;
}
function toBinary(byteValue) {
if (byteValue < 0) {
byteValue = byteValue & 0x00FF;
}
var str = byteValue.toString(2);
var len = str.length;
var prefix = "";
for (var i = len; i < 8; i++) {
prefix += "0";
}
return prefix + str;
}
我之前使用了 Joni的解决方案,它运行良好,但这个更短。
这个灵感来自于 Mozilla的Base64 Unicode讨论中第三个解决方案的atobUTF16()函数。
function convertStringToUTF8ByteArray(str) {
let binaryArray = new Uint8Array(str.length)
Array.prototype.forEach.call(binaryArray, function (el, idx, arr) { arr[idx] = str.charCodeAt(idx) })
return binaryArray
}
function utf8_toBinary(instr) {
//this is the same as unescape(encodeURIComponent(instr))
const binAry = (new TextEncoder().encode(instr));
let safeStr = String.fromCharCode(...binAry);
return btoa(safeStr);
}
function binary_toUtf8(binstr) {
let safeStr = atob(binstr);
let arr = new Uint8Array(safeStr.length);
for (let i = 0; i < safeStr.length; i++) {
arr[i] = safeStr.charCodeAt(i);
}
return new TextDecoder().decode(arr);
}
function convertByte()
{
var c=document.getElementById("str").value;
var arr = [];
var i=0;
for(var ind=0;ind<c.length;ind++)
{
arr[ind]=c.charCodeAt(i);
i++;
}
document.getElementById("result").innerHTML="The converted value is "+arr.join("");
}
unescape(encodeURIComponent())
不同。https://dev59.com/7GMl5IYBdhLWcg3wDjSg#18729536 - don kakafor
循环之后,它应该与arr
进行比较匹配。http://jsfiddle.net/3Uz8n/ - Jonathan Lonowski