在javascript中将字节数组转换为字符串


79

如何将字节数组转换为字符串?

我发现这些功能相反:

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

但是,如何使功能以其他方式起作用?

谢谢。

o


您要将字节数组转换为字符串,还是将位数组转换为字符串?
mcandre'7

另请参见utf8数组的正确解决方案:Uint8Array转换为Javascript中的字符串
Vadzim

Answers:


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 2010年

1
2)之所以需要进行这些转换,是因为我正在捕获一个签名,并且必须将其转换以填充数据库中的BLOB字段。问题是,尽管这两个功能正常工作,但其他地方还是出了问题。最主要的是,当我从数据库中检索BLOB时,它会进入一个bytes数组对象。但是,当我通过原始函数运行BLOB之后将BLOB写入数据库时​​,它不是字节数组对象。这可能是导致问题的原因。有任何想法吗?
user385579 2010年


4
String.fromCharCode.apply(String, array)对于Safari中很长的字符串是不安全的。JavaScriptCore中存在一个问题,这意味着函数不能接受超过65536个参数,否则将引发RangeError。它还将浏览器锁定在比其稍小的阵列上。参见bugs.webkit.org/show_bug.cgi?id=80797
马修(Matthew)

3
多字节utf-8字符失败,即: bin2String([0xE2, 0x98, 0xB9])
Brad Kent

48

只需apply将您的字节数组移至即可String.fromCharCode。例如

String.fromCharCode.apply(null, [102, 111, 111]) 等于'foo'。

警告:适用于小于65535的数组。MDN文档在此处


这已经在6年前的公认答案中得到了证明。
Balthazar

2
啊,的确,我错过了那条线。基本上,我正在寻找一个简短的单行代码,因此我驳斥了冗长且经过编辑的答案(也许太仓促)。
Bogdan D

哦,这很有意义:)
Balthazar

11
即使重复,它的简洁也使其比公认的答案更好。
Rich Apodaca

22

尝试使用新的文本编码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支持,则可以使用MDN网站推荐的FastestSmallestTextEncoderDecoder polyfill
Rosberg Linhares


8

该string2Bin可以简洁地编写,并且没有任何循环,可以启动!

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

1
很想知道添加的函数调用是否会减慢速度。
2013年

36
它仍然有一个循环,只是隐藏在map()中。
Johannes Lumpe 2013年

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不支持此功能!
tedebus '19

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,因为每个字节将分别转换为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编码的,并且您不能使用TextDecoder API,因为IE不支持它

  1. 您可以使用Mozilla开发人员网络网站推荐的FastestSmallestTextEncoderDecoder polyfill
  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);


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.