Advanced-Frontend / Daily-Interview-Question

我是依扬(木易杨),公众号「高级前端进阶」作者,每天搞定一道前端大厂面试题,祝大家天天进步,一年后会看到不一样的自己。

Home Page:https://muyiy.cn/question/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

第 144 题:手写二进制转 Base64

igoryaodev opened this issue · comments

base64编码

let  binaryDataToBase64 = byte => {
     let sBytes =  new Uint8Array(byte).reduce((accu,next)=> {
         retrun accu + String.fromCharCode(next)
}, '')
    return `data:image/png;base64,${btoa(sBytes)}` 
}
String.fromCharCode(...new Uint8Array(response.data))

https://blackstar.coding.me/2018-08-23-arraybuffer-to-base64orblob.html

String.fromCharCode(...new Uint8Array(response.data))

https://blackstar.coding.me/2018-08-23-arraybuffer-to-base64orblob.html
使用Uint8Array的时候怎么确定分配的内存是够用啊,Uint8Array应该只能分配8位(一个字节)的内存吧

btoa

bota是一个工具函数吗

node 端:
toBase64:

Buffer.from('123').toString('base64')

decode:

Buffer.from('MTIz', 'base64').toString()

浏览器端:
toBase64

btoa('123')

decode

atob('MTIz')

btoa 和 atob 都是 window 上的方法,atob 全称 ascii to binary ,反之亦然

字符转二进制

function charToBinary(text) {
  var code = "";
  for (let i of text) {
    // 字符编码
    let number = i.charCodeAt().toString(2);
    // 1 bytes = 8bit,将 number 不足8位的0补上
    for (let a = 0; a <= 8 - number.length; a++) {
       number = 0 + number;
    }
    code += number;
  }
  return code;
}

二进制转Base64

// 将二进制数据每 6bit 位替换成一个 base64 字符
function binaryTobase64(code) {
  let base64Code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  let res = '';
  // 1 bytes = 8bit,6bit 位替换成一个 base64 字符
  // 所以每 3 bytes 的数据,能成功替换成 4 个 base64 字符
    
  // 对不足 24 bit (也就是 3 bytes) 的情况进行特殊处理
  if (code.length % 24 === 8) {
    code += '0000';
    res += '=='
  }
  if (code.length % 24 === 16) {
    code += '00';
    res += '='
  }

  let encode = '';
  // code 按 6bit 一组,转换为
  for (let i = 0; i < code.length; i += 6) {
    let item = code.slice(i, i + 6);
    encode += base64Code[parseInt(item, 2)];
  }
  return encode + res;
}

字符转Base64

function base64encode(text) {
  let base64Code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  let res = '';
  let i = 0;
  while (i < text.length) {
    let char1, char2, char3, enc1, enc2, enc3, enc4;
    
    // 三个字符一组,转二进制
    char1 = text.charCodeAt(i++); 
    char2 = text.charCodeAt(i++);
    char3 = text.charCodeAt(i++);

    enc1 = char1 >> 2; // 取第 1 字节的前 6 位
    
    // 三个一组处理
    if (isNaN(char2)) {
      // 只有 1 字节的时候
      enc2 = ((char1 & 3) << 4) | (0 >> 4);
      // 第65个字符用来代替补位的 = 号
      enc3 = enc4 = 64;
    } else if (isNaN(char3)) {
      // 只有 2 字节的时候
      enc2 = ((char1 & 3) << 4) | (char2 >> 4);
      enc3 = ((char2 & 15) << 2) | (0 >> 6);
      enc4 = 64;
    } else {
      enc2 = ((char1 & 3) << 4) | (char2 >> 4); // 取第 1 个字节的后 2 位(3 = 11 << 4 = 110000) + 第 2 个字节的前 4 位
      enc3 = ((char2 & 15) << 2) | (char3 >> 6); // 取第 2 个字节的后 4 位 (15 = 1111 << 2 = 111100) + 第 3 个字节的前 2 位
      enc4 = char3 & 63; // 取最后一个字节的最后 6 位 (63 = 111111)
    }
    
    // 转base64
    res += base64Code.charAt(enc1) + base64Code.charAt(enc2) + base64Code.charAt(enc3) + base64Code.charAt(enc4)
  }

  return res;
}

字符转Base64-最优解(window.btoa,window.atob)✅✅✅

let encodedData = window.btoa("this is a example");
console.log(encodedData); // dGhpcyBpcyBhIGV4YW1wbGU=

let decodeData = window.atob(encodedData);
console.log(decodeData); // this is a example
commented
function Base64Encode(string) {
    return btoa(encodeURIComponent(string).replace(/%([0-9A-F]{2})/g,
        (match, p1) => String.fromCharCode(`0x${p1}`)));
}
commented

window 方法 atob btoa

String.fromCharCode(...new Uint8Array(response.data))

https://blackstar.coding.me/2018-08-23-arraybuffer-to-base64orblob.html
使用Uint8Array的时候怎么确定分配的内存是够用啊,Uint8Array应该只能分配8位(一个字节)的内存吧

Uint8Array 并不表示分配的 ArrayBuffer 的大小,length 才是, 无符号8位整数,表示当前存放的内容的字节大小是单字节字符,即1个字节8位。对于超过 ASCII 128 位的字符就不够用了,除此之外,我们还需要知道 TypedArray 里存放的是什么?是 unicode 码点。

// 例如
var v = new Uint8Array(8)
v[0] = '我'.charCodeAt() // 码点是 25105
console.log(v[0]) // 17 并不是 25105,因为超过了 2^7 = 128 
v[0] = '1'.charCodeAt() // 码点是 49
console.log(v[0]) // 49

unicode 基本平面内的字符是兼容 ASCII 码的,但是超过128位后,是双字节字符,用 Uint16Array 来表示,对于 emoji 表情 4 字节字符,用 Uint32Array 来表示。

https://iming.work/detail/5b80acd70b61600062edc375

function mybtoa(data) {
    var result = [];
    var bArray = [];
    var baseTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghigklmnopqrstuvwxyz0123456789+/"
    for (let index = 0; index < data.length; index++) {
      bArray.push(data.charCodeAt(index).toString(2))
    }
    bArray = bArray.map(para => {
      while (para.length < 8) {
        para = "0" + para;
      }
      return para;
    })
    var str = bArray.join('');
    var addZero =3- (str.length/8)%3
    var addAscii='';

    for (let index = 0; index < str.length%6; index++) {
      str+='0'
    }
   
    for (let index = 0; index < addZero; index++) {
      addAscii+="=";
    }
    for (let index = 0; index < str.length; index += 6) {
      result.push(baseTable[parseInt(str.substr(index, 6), 2)]);

    }
    return result.join('')+addAscii
  }

commented
```js
String.fromCharCode(...new Uint8Array(response.data))

https://blackstar.coding.me/2018-08-23-arraybuffer-to-base64orblob.html

这里返回的字符串还需要用 window.btoa() 处理一下才能是 base64 编码的 ASCII 字符串吧

MDN Base64的编码与解码

由于 DOMString 是16位编码的字符串,所以如果有字符超出了8位ASCII编码的字符范围时,在大多数的浏览器中对Unicode字符串调用 window.btoa 将会造成一个 Character Out Of Range 的异常。有很多种方法可以解决这个问题:

第一种方法是将JavaScript的本机UTF-16字符串直接编码为base64(快速,可移植,干净)
第二种方法是将JavaScript的本机UTF-16字符串转换为UTF-8,然后将后者编码为base64(相对快速,可移植,干净)。
第三种方法是通过二进制字符串将JavaScript的本地UTF-16字符串直接编码为base64(非常快,相对可移植,非常紧凑)
第四种方法是转义整个字符串(使用UTF-8,请参见encodeURIComponent),然后对其进行编码(便携式,非标准)
第五种方法类似于第二种方法,但是使用第三方库
```js
String.fromCharCode(...new Uint8Array(response.data))

https://blackstar.coding.me/2018-08-23-arraybuffer-to-base64orblob.html

This is not a good solution. String.fromCharCode is used to transform utf-16 code to string.

来个字符串转二进制的函数:

function s2b(s) {
  return s.split('').map(c => c.charCodeAt(0).toString(2).padStart(8, 0)).join('');
}