Преобразование байтового массива в строку в JavaScript
Как преобразовать байтовый массив в строку?
Я нашел эти функции, которые делают обратное:
function string2Bin(s) {
var b = new Array();
var last = s.length;
for (var i = 0; i < last; i++) {
var d = s.charCodeAt(i);
if (d < 128)
b[i] = dec2Bin(d);
else {
var c = s.charAt(i);
alert(c + ' is NOT an ASCII character');
b[i] = -1;
}
}
return b;
}
function dec2Bin(d) {
var b = '';
for (var i = 0; i < 8; i++) {
b = (d%2) + b;
d = Math.floor(d/2);
}
return b;
}
Но как мне заставить функции работать по-другому?
Благодарю.
Шао
16 ответов
Вам нужно проанализировать каждый октет обратно в число и использовать это значение, чтобы получить символ, что-то вроде этого:
function bin2String(array) {
var result = "";
for (var i = 0; i < array.length; i++) {
result += String.fromCharCode(parseInt(array[i], 2));
}
return result;
}
bin2String(["01100110", "01101111", "01101111"]); // "foo"
// Using your string2Bin function to test:
bin2String(string2Bin("hello world")) === "hello world";
Изменить: Да, ваш текущий string2Bin
можно написать более коротко:
function string2Bin(str) {
var result = [];
for (var i = 0; i < str.length; i++) {
result.push(str.charCodeAt(i).toString(2));
}
return result;
}
Но, глядя на документацию, на которую вы ссылались, я думаю, что setBytesParameter
Метод ожидает, что массив BLOB-объектов содержит десятичные числа, а не битовую строку, поэтому вы можете написать что-то вроде этого:
function string2Bin(str) {
var result = [];
for (var i = 0; i < str.length; i++) {
result.push(str.charCodeAt(i));
}
return result;
}
function bin2String(array) {
return String.fromCharCode.apply(String, array);
}
string2Bin('foo'); // [102, 111, 111]
bin2String(string2Bin('foo')) === 'foo'; // true
Просто apply
ваш байтовый массив для String.fromCharCode
, Например
String.fromCharCode.apply(null, [102, 111, 111])
равняется 'foo'.
Предостережение: работает для массивов короче 65535. Документы MDN здесь.
Попробуйте новый API кодирования текста:
// create an array view of some valid bytes
let bytesView = new Uint8Array([104, 101, 108, 108, 111]);
console.log(bytesView);
// convert bytes to string
// encoding can be specfied, defaults to utf-8 which is ascii.
let str = new TextDecoder().decode(bytesView);
console.log(str);
// convert string to bytes
// encoding can be specfied, defaults to utf-8 which is ascii.
let bytes2 = new TextEncoder().encode(str);
// look, they're the same!
console.log(bytes2);
console.log(bytesView);
Это должно работать:
String.fromCharCode(...array);
Или же
String.fromCodePoint(...array)
Эта строка2Bin может быть написана еще более кратко и без каких-либо циклов для загрузки!
function string2Bin ( str ) {
return str.split("").map( function( val ) {
return val.charCodeAt( 0 );
} );
}
Строка в байтовый массив: "FooBar".split('').map(c => c.charCodeAt(0));
Байтовый массив в строку: [102, 111, 111, 98, 97, 114].map(c => String.fromCharCode(c)).join('');
Я думаю, что это будет более эффективным:
function toBinString (arr) {
var uarr = new Uint8Array(arr.map(function(x){return parseInt(x,2)}));
var strings = [], chunksize = 0xffff;
// There is a maximum stack size. We cannot call String.fromCharCode with as many arguments as we want
for (var i=0; i*chunksize < uarr.length; i++){
strings.push(String.fromCharCode.apply(null, uarr.subarray(i*chunksize, (i+1)*chunksize)));
}
return strings.join('');
}
Даже если я немного опоздаю, я думаю, что для будущих пользователей будет интересно поделиться некоторыми однострочными реализациями, которые я делал с помощью ES6.
Одна вещь, которую я считаю важной в зависимости от вашей среды и / или того, что вы будете делать с данными, - это сохранение полного байтового значения. Например, (5).toString(2)
дам тебе 101
, но полное двоичное преобразование в реальности 00000101
и именно поэтому вам может понадобиться создать leftPad
реализация для заполнения байта строки ведущими нулями. Но вам это может не понадобиться, как показали другие ответы.
Если вы запустите приведенный ниже фрагмент кода, вы увидите, что первым выводом будет преобразование abc
строка в байтовый массив и сразу же после этого преобразование указанного массива в соответствующую ему строку.
// For each byte in our array, retrieve the char code value of the binary value
const binArrayToString = array => array.map(byte => String.fromCharCode(parseInt(byte, 2))).join('')
// Basic left pad implementation to ensure string is on 8 bits
const leftPad = str => str.length < 8 ? (Array(8).join('0') + str).slice(-8) : str
// For each char of the string, get the int code and convert it to binary. Ensure 8 bits.
const stringToBinArray = str => str.split('').map(c => leftPad(c.charCodeAt().toString(2)))
const array = stringToBinArray('abc')
console.log(array)
console.log(binArrayToString(array))
Если ваш массив закодирован в UTF-8 и вы не можете использовать API TextDecoder, потому что он не поддерживается в IE:
- Вы можете использовать полифилл FastestSmallestTextEncoderDecoder, рекомендованный веб-сайтом Mozilla Developer Network;
- Вы можете использовать эту функцию, также предоставленную на сайте MDN:
function utf8ArrayToString(aBytes) {
var sView = "";
for (var nPart, nLen = aBytes.length, nIdx = 0; nIdx < nLen; nIdx++) {
nPart = aBytes[nIdx];
sView += String.fromCharCode(
nPart > 251 && nPart < 254 && nIdx + 5 < nLen ? /* six bytes */
/* (nPart - 252 << 30) may be not so safe in ECMAScript! So...: */
(nPart - 252) * 1073741824 + (aBytes[++nIdx] - 128 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
: nPart > 247 && nPart < 252 && nIdx + 4 < nLen ? /* five bytes */
(nPart - 248 << 24) + (aBytes[++nIdx] - 128 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
: nPart > 239 && nPart < 248 && nIdx + 3 < nLen ? /* four bytes */
(nPart - 240 << 18) + (aBytes[++nIdx] - 128 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
: nPart > 223 && nPart < 240 && nIdx + 2 < nLen ? /* three bytes */
(nPart - 224 << 12) + (aBytes[++nIdx] - 128 << 6) + aBytes[++nIdx] - 128
: nPart > 191 && nPart < 224 && nIdx + 1 < nLen ? /* two bytes */
(nPart - 192 << 6) + aBytes[++nIdx] - 128
: /* nPart < 127 ? */ /* one byte */
nPart
);
}
return sView;
}
let str = utf8ArrayToString([50,72,226,130,130,32,43,32,79,226,130,130,32,226,135,140,32,50,72,226,130,130,79]);
// Must show 2H₂ + O₂ ⇌ 2H₂O
console.log(str);
Если вы используете node.js, вы можете сделать это:
yourByteArray.toString('base64');
Слишком поздно, чтобы ответить, но если ваш ввод в виде байтов ASCII, то вы можете попробовать это решение:
function convertArrToString(rArr){
//Step 1: Convert each element to character
let tmpArr = new Array();
rArr.forEach(function(element,index){
tmpArr.push(String.fromCharCode(element));
});
//Step 2: Return the string by joining the elements
return(tmpArr.join(""));
}
function convertArrToHexNumber(rArr){
return(parseInt(convertArrToString(rArr),16));
}
У меня были некоторые расшифрованные массивы байтов с символами заполнения и другие вещи, которые мне не нужны, поэтому я сделал это (вероятно, не идеально, но это работает для моего ограниченного использования)
var junk = String.fromCharCode.apply(null, res).split('').map(char => char.charCodeAt(0) <= 127 && char.charCodeAt(0) >= 32 ? char : '').join('');
Не найдено ни одного решения, которое бы работало с символами UTF-8. String.fromCharCode
это хорошо, пока вы не встретите 2-байтовый символ.
Например, Hüser придет как [0x44,0x61,0x6e,0x69,0x65,0x6c,0x61,0x20,0x48,0xc3,0xbc,0x73,0x65,0x72]
Но если вы пройдете через это с String.fromCharCode
у вас будет Hüser, поскольку каждый байт будет преобразован в символ отдельно.
Решение
В настоящее время я использую следующее решение:
function pad(n) { return (n.length < 2 ? '0' + n : n); }
function decodeUtf8(data) {
return decodeURIComponent(
data.map(byte => ('%' + pad(byte.toString(16)))).join('')
);
}
То, что вы ищете, это String.fromCharCode
То, что вы хотите сделать, это перебрать массив байтов (представленный как целые числа), создать строковый эквивалент и добавить его к результату:
> const stringToBin = (str) => [...str].map(item=>item.charCodeAt())
> undefined
> stringToBin('hello')
> (5) [104, 101, 108, 108, 111]
> const binToString = (array) => String.fromCharCode(...array)
> undefined
> binToString(stringToBin('hello'))
> 'hello'
Самое простое решение, которое я нашел:
var text = atob(byteArray);