2011-06-03 179 views
56

如何使用JavaScript將字符串轉換爲bytearray。輸出應該等於下面的C#代碼。如何將字符串轉換爲Bytearray

UnicodeEncoding encoding = new UnicodeEncoding(); 
byte[] bytes = encoding.GetBytes(AnyString); 

由於UnicodeEncoding默認爲使用Little-Endianness的UTF-16。

編輯:我有一個要求,使用上面的C#代碼來匹配生成的bytearray客戶端和服務器端生成的客戶端。

+2

的JavaScript是不完全的最知名的易於使用的BLOB使用 - 你爲什麼不只是發送字符串的JSON? – 2011-06-03 10:58:31

+2

Javascript字符串是UTF-16,還是您已經知道了? – Kevin 2011-06-03 11:02:49

+2

首先爲什麼你需要在JavaScript中轉換此? – BreakHead 2011-06-03 11:07:06

回答

12

在C#運行此

UnicodeEncoding encoding = new UnicodeEncoding(); 
byte[] bytes = encoding.GetBytes("Hello"); 

將創建

72,0,101,0,108,0,108,0,111,0 

byte array

陣列對於一個字符其中碼是大於255它看起來像這樣

byte array

如果你想在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(', '));

+1

我已經試過這個,但是這給了我不同於上面的C#代碼的結果。就像這種情況一樣,C#代碼輸出字節數組是= 72,0,101,0,108,0,108,0,111,0 我有兩個匹配的要求,所以那些工作不正常。 – shas 2011-06-03 11:55:47

+0

@shas,似乎是相同的,只是在每個字符後加上一個'0'。更新後的答案現在應該和'c#'一樣。 – BrunoLM 2011-06-03 12:12:27

+0

我得到了未定義的JS錯誤str [i]。你正在嘗試訪問什麼。不應該是str.charCodeAt(i)? – shas 2011-06-03 12:33:04

1

下面是同樣的功能@BrunoLM貼轉換爲字符串函數原型:

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(); 
+27

這仍然是不正確的,就像它引用的答案一樣。 charCodeAt不返回一個字節。將大於255的值推入稱爲「字節」的數組是沒有意義的;非常誤導。這個函數根本不執行編碼,只是將字符代碼粘貼到一個數組中。要執行UTF16編碼,您必須檢查字符代碼,決定是否需要用2個字節或4個字節來表示它(因爲UTF16是可變長度編碼),然後將每個字節單獨寫入數組。 – Triynko 2013-08-06 21:20:55

+8

另外,修改原生數據類型的原型也是不好的做法。 – 2013-10-30 18:18:31

+0

@AndrewLundin,這是interresting ...說誰? – Jerther 2015-02-06 19:06:27

11

我想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,爪哇String.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標記G CLEF(BPM外部,從而不僅考慮2 UTF-16字節,但是4.

當前JavaScript版本在內部使用「UCS-2」,因此此符號佔用2個正常字符的空間。

我不確定,但在使用charCodeAt時,看起來我們得到了UTF-16中使用的替代代碼點,因此非BPM字符可以正確處理。

這個問題是絕對不平凡的。它可能取決於使用的JavaScript版本和引擎。所以,如果你想可靠的解決方案,你應該看看:

+1

仍然不是一個完整的答案。 UTF16是一種可變長度編碼,它使用16位塊來表示字符。單個字符將被編碼爲2個字節或4個字節,具體取決於charcter代碼值的大小。由於此函數最多可以寫入2個字節,因此無法處理所有Unicode字符代碼點,並且不是一個完整的UTF16編碼實現,而不是一個長鏡頭。 – Triynko 2013-08-06 21:24:08

+0

@Triynko我的編輯和測試後,你仍然認爲這不是完整的答案?如果是,你有答案嗎? – hgoebl 2013-11-09 14:18:13

+1

@Triynko你是一半的權利,但實際上這個答案確實工作正常。 JavaScript字符串實際上不是Unicode代碼點的序列,它們是UTF-16代碼單元的序列。儘管有這個名字,'charCodeAt'返回一個UTF-16代碼單元,範圍在0-65535之間。 2字節範圍以外的字符表示爲代理對,就像在UTF-16中一樣。 (順便說一下,對於包括Java和C#在內的其他幾種語言的字符串也是如此。) – 2016-04-03 19:49:11

0

最好的解決方案我(當然最有可能的原油)會是:

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; 
} 

雖然我注意到這個問題已經在這裏一年多了。

+2

這不能正常工作。變長字符邏輯不正確,UTF-16中沒有8位字符。儘管有這個名字,'charCodeAt'返回一個16位的UTF-16 Code Unit,所以你不需要任何可變長度的邏輯。您可以調用charCodeAt,將結果拆分爲兩個8位字節,並將它們填充到輸出數組中(自從問題詢問UTF-16LE以來,先將最低字節先填入)。 – 2016-04-03 19:58:14

-1

你不需要下劃線,只需使用內置地圖:

var string = 'Hello World!'; 
 

 
document.write(string.split('').map(function(c) { return c.charCodeAt(); }));

+0

這將返回一個16位數字的數組,表示該字符串爲UTF-16代碼點的序列。這不是OP要求的,但至少它讓你在那裏分道揚part。 – 2016-07-13 11:27:29

0

我知道這個問題幾乎是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());

+1

這類作品,但是非常具有誤導性。 'bytes'數組不包含'bytes',它包含16位數字,代表UTF-16代碼單元中的字符串。這幾乎是問題的要求,但只是偶然。 – 2016-04-03 20:07:54

7

靈感來自@ hgoebl的回答。他的代碼是UTF-16,我需要一些US-ASCII。所以這裏有一個更完整的答案,涵蓋US-ASCII,UTF-16和UTF-32。

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; 
} 
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; 
} 
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(和諧)提案的一部分。由於charCodeAt返回2個字節,這些字符比US-ASCII可能表示的字符多,所以函數stringToAsciiByteArray將引發這種情況,而不是將字符分成兩半,並取其中一個或兩個字節。

請注意,這個答案是不平凡的,因爲字符編碼是不平凡的。你想要什麼樣的字節數組取決於你想要這些字節代表什麼字符編碼。

javascript有內部使用UTF-16或UCS-2的選項,但由於它具有像UTF-16一樣的方法,所以我不明白爲什麼任何瀏覽器都會使用UCS-2。 另請參閱:https://mathiasbynens.be/notes/javascript-encoding

是的我知道問題是4歲,但我需要這個答案爲我自己。

14

如果您正在尋找在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); 
+2

這是爲node.js,但我認爲這個問題是尋找一個在瀏覽器中工作的解決方案。儘管如此,它確實能夠正常工作,不像其他大多數對這個問題的答案,所以+1。 – 2016-04-03 19:34:14

+2

沒有這樣的功能BTW:/當OP沒有這個對象時,新的「緩衝」,你甚至沒有顯示它。誰投票贊成這樣的答案?問題在Javascript上,而不是Node.js - 你不能在jsfiddle或html/.js文件中使用它,並期望它可以工作。只需要NO – 2016-09-28 05:50:24

1

既然不能對答案進行評論,我會建立在金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

因此,湯姆Stickel的反對無效,答案確實是一個有效的答案。

0

2018年最簡單的方法應該是TextEncoder,但返回的元素不是字節數組,它是Uint8Array。 (並非所有的瀏覽器都支持它)

let utf8Decode = new TextDecoder('utf-8'); 
utf8Encode.encode("eee") 
> Uint8Array [ 101, 101, 101 ] 
1
String.prototype.encodeHex = function() { 
    return this.split('').map(e => e.charCodeAt()) 
}; 

String.prototype.decodeHex = function() {  
    return this.map(e => String.fromCharCode(e)).join('') 
}; 
+4

如果您提供一些文本以與代碼一起解釋爲什麼可以選擇此方法而不是其他答案之一,這將會很有幫助。 – NightOwl888 2018-02-16 20:27:40

+0

這種方法比其他方法簡單,但也是這樣,這就是我沒有寫任何東西的原因。 – 2018-02-20 14:30:52