Перетворення байтового масиву у рядок у 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;
}

Але як я можу змусити функції працювати по-іншому?

Дякую.

Шао


Ви хочете перетворити байтовий масив у рядок або масив бітів у рядок?
mcandre

Див. Також належне рішення для масиву 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

1
2) Причина, по якій мені потрібні ці перетворення, полягає в тому, що я фіксую підпис, і я повинен перетворити його, щоб заповнити поле BLOB у базі даних. Проблема в тому, що, поки ці 2 функції працюють, щось інше йде не так. Головне, що коли я отримую BLOB з бази даних, він потрапляє в байт-об'єкт масиву. Однак, коли я записую BLOB в базу даних після запуску його через вихідну функцію, це не байтовий об'єкт масиву. Це може бути причиною проблеми. Будь-які ідеї?
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 років тому.
Бальтазар

2
ааа, справді, я пропустив цей рядок. В основному я шукав короткий лайнер і відхилив цю довгу та відредаговану відповідь (можливо, занадто поспішну).
Богдан Д

О гаразд, це має сенс :)
Бальтазар

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 .
Росберг


8

Це string2Bin можна записати ще більш коротко, і без будь - яких петель, для завантаження!

function string2Bin ( str ) {
    return str.split("").map( function( val ) { 
        return val.charCodeAt( 0 ); 
    } );
}

1
Було б цікаво дізнатись, чи додані виклики функцій сповільнюють це.
jocull

36
Він все ще має цикл, він просто прихований у map ().
Йоханнес Лумпе

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('');
}

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('');


будьте обережні, це не підтримується IE!
тедебус

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-байтовий символ.

Наприклад 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('')
  );
}

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


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.