如何使用JavaScript转换字节数组中的字符串。输出应等效于以下C#代码。
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] bytes = encoding.GetBytes(AnyString);
由于UnicodeEncoding默认为带有Little-Endianness的UTF-16。
编辑:我需要使用上面的C#代码将字节数组生成的客户端与服务器端生成的字节数组进行匹配。
如何使用JavaScript转换字节数组中的字符串。输出应等效于以下C#代码。
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] bytes = encoding.GetBytes(AnyString);
由于UnicodeEncoding默认为带有Little-Endianness的UTF-16。
编辑:我需要使用上面的C#代码将字节数组生成的客户端与服务器端生成的字节数组进行匹配。
Answers:
在C#中运行
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] bytes = encoding.GetBytes("Hello");
将创建一个数组
72,0,101,0,108,0,108,0,111,0

对于代码大于255的字符,它将如下所示

如果您希望在JavaScript中实现非常相似的行为,则可以执行此操作(v2是更强大的解决方案,而原始版本仅适用于0x00〜0xff)
var str = "Hello竜";
var bytes = []; // char codes
var bytesv2 = []; // char codes
for (var i = 0; i < str.length; ++i) {
var code = str.charCodeAt(i);
bytes = bytes.concat([code]);
bytesv2 = bytesv2.concat([code & 0xff, code / 256 >>> 0]);
}
// 72, 101, 108, 108, 111, 31452
console.log('bytes', bytes.join(', '));
// 72, 0, 101, 0, 108, 0, 108, 0, 111, 0, 220, 122
console.log('bytesv2', bytesv2.join(', '));
如果您正在寻找可以在node.js中使用的解决方案,则可以使用以下方法:
var myBuffer = [];
var str = 'Stack Overflow';
var buffer = new Buffer(str, 'utf16le');
for (var i = 0; i < buffer.length; i++) {
myBuffer.push(buffer[i]);
}
console.log(myBuffer);
我想C#和Java产生相等的字节数组。如果您使用非ASCII字符,则仅添加一个0是不够的。我的示例包含一些特殊字符:
var str = "Hell ö € Ω 𝄞";
var bytes = [];
var charCode;
for (var i = 0; i < str.length; ++i)
{
charCode = str.charCodeAt(i);
bytes.push((charCode & 0xFF00) >> 8);
bytes.push(charCode & 0xFF);
}
alert(bytes.join(' '));
// 0 72 0 101 0 108 0 108 0 32 0 246 0 32 32 172 0 32 3 169 0 32 216 52 221 30
我不知道C#是否放置BOM(字节顺序标记),但是如果使用UTF-16,JavaString.getBytes将添加以下字节:254 255。
String s = "Hell ö € Ω ";
// now add a character outside the BMP (Basic Multilingual Plane)
// we take the violin-symbol (U+1D11E) MUSICAL SYMBOL G CLEF
s += new String(Character.toChars(0x1D11E));
// surrogate codepoints are: d834, dd1e, so one could also write "\ud834\udd1e"
byte[] bytes = s.getBytes("UTF-16");
for (byte aByte : bytes) {
System.out.print((0xFF & aByte) + " ");
}
// 254 255 0 72 0 101 0 108 0 108 0 32 0 246 0 32 32 172 0 32 3 169 0 32 216 52 221 30
编辑:
添加了特殊字符(U + 1D11E)MUSICAL SYMBOL G CLEF(BPM之外),因此在UTF-16中不仅占用2个字节,而且占用4个字节。
当前的JavaScript版本内部使用“ UCS-2”,因此此符号占用2个普通字符的空间。
我不确定,但使用时 charCodeAt它,我们似乎可以确切地获得UTF-16中也使用的替代代码点,因此可以正确处理非BPM字符。
这个问题绝对是不容易的。它可能取决于所使用的JavaScript版本和引擎。因此,如果您需要可靠的解决方案,则应该看看:
charCodeAt返回的是UTF-16代码单元,范围为0-65535。就像UTF-16中一样,2字节范围以外的字符表示为代理对。(顺便说一句,其他几种语言的字符串也是如此,包括Java和C#。)
(charCode & 0xFF00) >> 8是多余的,您无需在转移之前将其屏蔽。
2018年最简单的方法应该是TextEncoder,但是返回的元素不是字节数组,而是Uint8Array。(并非所有浏览器都支持它)
let utf8Encode = new TextEncoder();
utf8Encode.encode("eee")
> Uint8Array [ 101, 101, 101 ]
new TextDecoder().decode(new TextEncoder().encode(str)) == str。
JavaScript将字符串编码为UTF-16,就像C#一样UnicodeEncoding,因此字节数组应使用完全匹配charCodeAt(),并将每个返回的字节对拆分为2个单独的字节,如下所示:
function strToUtf16Bytes(str) {
const bytes = [];
for (ii = 0; ii < str.length; ii++) {
const code = str.charCodeAt(ii); // x00-xFFFF
bytes.push(code & 255, code >> 8); // low, high
}
return bytes;
}
例如:
strToUtf16Bytes('🌵');
// [ 60, 216, 53, 223 ]
但是,如果要获取UTF-8字节数组,则必须对字节进行转码。
该解决方案听起来有些微不足道,但是我在高流量的生产环境中使用了以下代码,并取得了巨大的成功(原始来源)。
此外,对于感兴趣的读者,我发布了unicode帮助器,可帮助我处理其他语言(例如PHP)报告的字符串长度。
/**
* Convert a string to a unicode byte array
* @param {string} str
* @return {Array} of bytes
*/
export function strToUtf8Bytes(str) {
const utf8 = [];
for (let ii = 0; ii < str.length; ii++) {
let charCode = str.charCodeAt(ii);
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));
} else {
ii++;
// Surrogate pair:
// 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(ii) & 0x3ff));
utf8.push(
0xf0 | (charCode >> 18),
0x80 | ((charCode >> 12) & 0x3f),
0x80 | ((charCode >> 6) & 0x3f),
0x80 | (charCode & 0x3f),
);
}
}
return utf8;
}
受到@hgoebl的回答的启发。他的代码用于UTF-16,而我需要一些用于US-ASCII的代码。因此,这里有一个更完整的答案,涵盖了US-ASCII,UTF-16和UTF-32。
/**@returns {Array} bytes of US-ASCII*/
function stringToAsciiByteArray(str)
{
var bytes = [];
for (var i = 0; i < str.length; ++i)
{
var charCode = str.charCodeAt(i);
if (charCode > 0xFF) // char > 1 byte since charCodeAt returns the UTF-16 value
{
throw new Error('Character ' + String.fromCharCode(charCode) + ' can\'t be represented by a US-ASCII byte.');
}
bytes.push(charCode);
}
return bytes;
}
/**@returns {Array} bytes of UTF-16 Big Endian without BOM*/
function stringToUtf16ByteArray(str)
{
var bytes = [];
//currently the function returns without BOM. Uncomment the next line to change that.
//bytes.push(254, 255); //Big Endian Byte Order Marks
for (var i = 0; i < str.length; ++i)
{
var charCode = str.charCodeAt(i);
//char > 2 bytes is impossible since charCodeAt can only return 2 bytes
bytes.push((charCode & 0xFF00) >>> 8); //high byte (might be 0)
bytes.push(charCode & 0xFF); //low byte
}
return bytes;
}
/**@returns {Array} bytes of UTF-32 Big Endian without BOM*/
function stringToUtf32ByteArray(str)
{
var bytes = [];
//currently the function returns without BOM. Uncomment the next line to change that.
//bytes.push(0, 0, 254, 255); //Big Endian Byte Order Marks
for (var i = 0; i < str.length; i+=2)
{
var charPoint = str.codePointAt(i);
//char > 4 bytes is impossible since codePointAt can only return 4 bytes
bytes.push((charPoint & 0xFF000000) >>> 24);
bytes.push((charPoint & 0xFF0000) >>> 16);
bytes.push((charPoint & 0xFF00) >>> 8);
bytes.push(charPoint & 0xFF);
}
return bytes;
}
UTF-8是可变长度的,不包含在内,因为我必须自己编写编码。UTF-8和UTF-16是可变长度的。顾名思义,UTF-8,UTF-16和UTF-32的位数最少。如果UTF-32字符的代码点为65,则意味着有3个前导0。但是用于UTF-16的相同代码只有1个前导0。另一方面,US-ASCII是固定宽度的8位,这意味着它可以直接转换为字节。
String.prototype.charCodeAt返回最大2个字节的数目,并完全匹配UTF-16。但是,对于UTF-32 String.prototype.codePointAt,这是ECMAScript 6(Harmony)建议的一部分。因为charCodeAt返回2个字节,这比US-ASCII可以表示的字符更多,所以stringToAsciiByteArray在这种情况下,该函数将抛出该字符,而不是将字符分成两半并占用一个或两个字节。
注意,这个答案是不平凡的,因为字符编码是不平凡的。您想要哪种字节数组取决于您希望这些字节表示哪种字符编码。
javascript可以选择在内部使用UTF-16或UCS-2,但是由于它具有的行为类似于UTF-16,因此我看不到为什么任何浏览器都会使用UCS-2。另请参阅:https : //mathiasbynens.be/notes/javascript-encoding
是的,我知道这个问题已有4岁,但我自己需要这个答案。
'02'在[ 48, 0, 50, 0 ]哪里。哪一个是正确的?stringToUtf16ByteArray[ 0, 48, 0, 50 ]
由于我无法对答案发表评论,因此我将基于Jin Izzraeel的答案
var myBuffer = [];
var str = 'Stack Overflow';
var buffer = new Buffer(str, 'utf16le');
for (var i = 0; i < buffer.length; i++) {
myBuffer.push(buffer[i]);
}
console.log(myBuffer);
说如果您想在浏览器中使用Node.js缓冲区,则可以使用它。
https://github.com/feross/buffer
因此,汤姆·斯蒂克尔(Tom Stickel)的反对是无效的,答案的确是有效的答案。
String.prototype.encodeHex = function () {
return this.split('').map(e => e.charCodeAt())
};
String.prototype.decodeHex = function () {
return this.map(e => String.fromCharCode(e)).join('')
};
encodeHex将返回一个16位数字数组,而不是字节。
我当场想出的最佳解决方案(尽管最有可能是粗略的)是:
String.prototype.getBytes = function() {
var bytes = [];
for (var i = 0; i < this.length; i++) {
var charCode = this.charCodeAt(i);
var cLen = Math.ceil(Math.log(charCode)/Math.log(256));
for (var j = 0; j < cLen; j++) {
bytes.push((charCode << (j*8)) & 0xFF);
}
}
return bytes;
}
尽管我注意到这个问题已经存在了一年多。
charCodeAt返回的是16位UTF-16代码单元,因此您不需要任何可变长度逻辑。您可以只调用charCodeAt,将结果分成两个8位字节,然后将它们填充到输出数组中(因为问题要求输入UTF-16LE,因此最低位在前)。
我知道这个问题将近4岁了,但这对我来说很顺利:
String.prototype.encodeHex = function () {
var bytes = [];
for (var i = 0; i < this.length; ++i) {
bytes.push(this.charCodeAt(i));
}
return bytes;
};
Array.prototype.decodeHex = function () {
var str = [];
var hex = this.toString().split(',');
for (var i = 0; i < hex.length; i++) {
str.push(String.fromCharCode(hex[i]));
}
return str.toString().replace(/,/g, "");
};
var str = "Hello World!";
var bytes = str.encodeHex();
alert('The Hexa Code is: '+bytes+' The original string is: '+bytes.decodeHex());
或者,如果您只想使用字符串而不使用数组,则可以使用:
String.prototype.encodeHex = function () {
var bytes = [];
for (var i = 0; i < this.length; ++i) {
bytes.push(this.charCodeAt(i));
}
return bytes.toString();
};
String.prototype.decodeHex = function () {
var str = [];
var hex = this.split(',');
for (var i = 0; i < hex.length; i++) {
str.push(String.fromCharCode(hex[i]));
}
return str.toString().replace(/,/g, "");
};
var str = "Hello World!";
var bytes = str.encodeHex();
alert('The Hexa Code is: '+bytes+' The original string is: '+bytes.decodeHex());
bytes数组不包含“字节”,它包含16位数字,以UTF-16代码单位表示字符串。这几乎是问题所要的,但实际上只是偶然。
这与@BrunoLM发布的转换为String原型函数的函数相同:
String.prototype.getBytes = function () {
var bytes = [];
for (var i = 0; i < this.length; ++i) {
bytes.push(this.charCodeAt(i));
}
return bytes;
};
如果您这样定义函数,则可以在任何字符串上调用.getBytes()方法:
var str = "Hello World!";
var bytes = str.getBytes();
您不需要下划线,只需使用内置地图即可:
var string = 'Hello World!';
document.write(string.split('').map(function(c) { return c.charCodeAt(); }));