Преобразование байтового массива в строку в javascript

81

Как преобразовать массив байтов в строку?

Я нашел эти функции, которые делают обратное:

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

Но как мне заставить функции работать по-другому?

Благодарю.

Шао

user385579
источник
Вы хотите преобразовать массив байтов в строку или массив битов в строку?
mcandre 07
Смотрите также правильное решение для массива utf8: Uint8Array в строку в JavaScript
Вадиму

Ответы:

82

Вам нужно преобразовать каждый октет обратно в число и использовать это значение для получения символа, примерно так:

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
Кристиан К. Сальвадо
источник
Спасибо за сверхскоростной ответ. Пара вопросов ... 1) Ваша функция bin2String впечатляет - всего 5 строк кода. Можно ли изменить функцию string2bin, чтобы использовать больше функций Javascript для сокращения функции и подфункции? .....
user385579 07
1
2) Причина, по которой мне нужны эти преобразования, заключается в том, что я собираю подпись, и мне нужно преобразовать ее, чтобы заполнить поле BLOB в базе данных. Проблема в том, что пока эти 2 функции работают, что-то еще не так. Главное, что когда я получаю большой двоичный объект из базы данных, он переходит в объект массива байтов. Однако когда я записываю большой двоичный объект в базу данных после его выполнения с помощью исходной функции, это не объект массива байтов. Это может быть причиной проблемы. Есть идеи?
user385579 07
dcx.sybase.com/index.html#1101en/ulmbus_en11/… Это синтаксис, который я использую для установки данных.
user385579 07
4
String.fromCharCode.apply(String, array)небезопасно для очень длинных строк в Safari. В JavaScriptCore есть проблема, которая означает, что функции не могут принимать более 65536 аргументов, в противном случае будет выбрано RangeError. Он также блокирует браузер для массивов немного меньшего размера. См. Bugs.webkit.org/show_bug.cgi?id=80797
Матфей,
4
Ошибка для многобайтовых символов utf-8, например: bin2String([0xE2, 0x98, 0xB9])
Брэд Кент
49

Просто applyваш байтовый массив String.fromCharCode. Например

String.fromCharCode.apply(null, [102, 111, 111]) равно "foo".

Предостережение: работает для массивов короче 65535. Документация MDN здесь .

Богдан Д
источник
Это уже было продемонстрировано принятым ответом 6 лет назад.
Balthazar
2
ааа, действительно, я пропустил эту строчку. По сути, я искал короткий однострочный текст и отклонил этот длинный и отредактированный ответ (возможно, слишком поспешный).
Bogdan D
Ну ладно, в этом есть смысл :)
Бальтазар
11
Несмотря на повторение, его краткость делает его лучше, чем принятый ответ.
Rich Apodaca
23

Попробуйте новый 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);

Джеймс
источник
1
К сожалению, IE не поддерживает это.
Soul_man
Если вам нужна поддержка UTF-8 и IE, вы можете использовать полифилл FastestSmallestTextEncoderDecoder , рекомендованный сайтом MDN .
Rosberg Linhares
10

Это должно работать:

String.fromCharCode(...array);

Или же

String.fromCodePoint(...array)
Роули Фриман
источник
коротко и мило;)
abhisekp
8

Этот string2Bin можно записать еще более кратко и без каких-либо циклов!

function string2Bin ( str ) {
    return str.split("").map( function( val ) { 
        return val.charCodeAt( 0 ); 
    } );
}
cmcnulty
источник
1
Было бы любопытно посмотреть, замедляют ли это добавленные вызовы функций.
jocull
36
У него все еще есть цикл, он просто скрыт внутри map ().
Johannes Lumpe
4

Думаю, было бы эффективнее:

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('');
}
Lovasoa
источник
4

Даже если я немного опоздаю, я подумал, что будущим пользователям будет интересно поделиться некоторыми однострочными реализациями, которые я сделал с помощью 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))

Бальтазар
источник
3

Строка в байтовый массив: "FooBar".split('').map(c => c.charCodeAt(0));

Байтовый массив в строку: [102, 111, 111, 98, 97, 114].map(c => String.fromCharCode(c)).join('');

ZaksBack
источник
будьте осторожны, это не поддерживается IE!
tedebus 09
1

Слишком поздно отвечать, но если вы введены в виде байтов 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));
}
Индия
источник
1

Если вы используете node.js, вы можете сделать это:

yourByteArray.toString('base64');
Канер
источник
0

Не нашел решения, которое бы работало с символами UTF-8. String.fromCharCodeхорошо, пока вы не встретите 2-байтовый символ.

Например, Хюзер придет как[0x44,0x61,0x6e,0x69,0x65,0x6c,0x61,0x20,0x48,0xc3,0xbc,0x73,0x65,0x72]

Но если вы пройдете через это, у String.fromCharCodeвас будет Hüser, поскольку каждый байт будет преобразован в char отдельно.

Решение

В настоящее время я использую следующее решение:

function pad(n) { return (n.length < 2 ? '0' + n : n); }
function decodeUtf8(data) {
  return decodeURIComponent(
    data.map(byte => ('%' + pad(byte.toString(16)))).join('')
  );
}
Душевный человек
источник
0

У меня было несколько расшифрованных байтовых массивов с символами заполнения и другими вещами, которые мне не нужны, поэтому я сделал это (вероятно, не идеально, но это работает для моего ограниченного использования)

var junk = String.fromCharCode.apply(null, res).split('').map(char => char.charCodeAt(0) <= 127 && char.charCodeAt(0) >= 32 ? char : '').join('');
ИгнусФаст
источник
0

Если ваш массив закодирован в UTF-8 и вы не можете использовать API TextDecoder, потому что он не поддерживается в IE :

  1. Вы можете использовать полифилл FastestSmallestTextEncoderDecoder, рекомендованный веб-сайтом Mozilla Developer Network ;
  2. Вы можете использовать эту функцию, также представленную на сайте 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);

Росберг Линьярес
источник
0

Самое простое решение, которое я нашел:

var text = atob(byteArray);
Уильям Хэмпшир
источник