in

Codificación y decodificación Base64 en Javascript del lado del cliente

apple touch icon@2

¿Alguien dijo golf en código? =)

El siguiente es mi intento de mejorar mi handicap mientras me pongo al día. Suministrado para su conveniencia.

function decode_base64(s) {
  var b=l=0, r="",
  m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  s.split('').forEach(function (v) {
    b=(b<<6)+m.indexOf(v); l+=6;
    if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
  });
  return r;
}

Lo que en realidad buscaba era una implementación asincrónica y, para mi sorpresa, resulta forEach a diferencia de JQuery’s $([]).each La implementación del método es muy síncrona.

Si también tenías estas locas nociones en mente, un retraso de 0 window.setTimeout ejecutará la decodificación base64 de forma asincrónica y ejecutará la función de devolución de llamada con el resultado cuando haya terminado.

function decode_base64_async(s, cb) {
  setTimeout(function () { cb(decode_base64(s)); }, 0);
}

@Toothbrush sugirió «indexar una cadena como una matriz» y deshacerse del split. Esta rutina parece realmente extraña y no estoy seguro de cuán compatible será, pero golpeó otro birdie, así que hagámoslo.

function decode_base64(s) {
  var b=l=0, r="",
  m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  [].forEach.call(s, function (v) {
    b=(b<<6)+m.indexOf(v); l+=6;
    if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
  });
  return r;
}

Mientras trataba de encontrar más información sobre la cadena de JavaScript como matriz, me topé con este consejo profesional usando un /./g regex para recorrer una cadena. Esto reduce aún más el tamaño del código al reemplazar la cadena en su lugar y eliminar la necesidad de mantener una variable de retorno.

function decode_base64(s) {
  var b=l=0,
  m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  return s.replace(/./g, function (v) {
    b=(b<<6)+m.indexOf(v); l+=6;
    return l<8?'':String.fromCharCode((b>>>(l-=8))&0xff);
  });
}

Sin embargo, si estaba buscando algo un poco más tradicional, quizás lo siguiente sea más de su gusto.

function decode_base64(s) {
  var b=l=0, r="", s=s.split(''), i,
  m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  for (i in s) {
    b=(b<<6)+m.indexOf(s[i]); l+=6;
    if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
  }
  return r;
}

No tuve el problema de nulo final, por lo que se eliminó para permanecer por debajo del par, pero debería resolverse fácilmente con un trim() o un trimRight() si lo prefiere, si esto le supone un problema.

es decir.

return r.trimRight();

Nota:

El resultado es una cadena de bytes ascii, si necesita unicode, lo más fácil es escape la cadena de bytes que luego se puede decodificar con decodeURIComponent para producir la cadena Unicode.

function decode_base64_usc(s) {      
  return decodeURIComponent(escape(decode_base64(s)));
}

Ya que escape está siendo obsoleto, podríamos cambiar nuestra función para admitir unicode directamente sin la necesidad de escape o String.fromCharCode podemos producir un % cadena de escape lista para la decodificación URI.

function decode_base64(s) {
  var b=l=0,
  m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  return decodeURIComponent(s.replace(/./g, function (v) {
    b=(b<<6)+m.indexOf(v); l+=6;
    return l<8?'':'%'+(0x100+((b>>>(l-=8))&0xff)).toString(16).slice(-2);
  }));
}

Editar para @Charles Byrne:

No recuerdo por qué no ignoramos los caracteres de relleno ‘=’, podría haber funcionado con una especificación que no los requería en ese momento. Si tuviéramos que modificar el decodeURIComponent rutina para ignorar estos, como deberíamos ya que no representan ningún dato, el resultado decodifica el ejemplo correctamente.

function decode_base64(s) {
  var b=l=0,
  m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  return decodeURIComponent(s.replace(/=*$/,'').replace(/./g, function (v) {
    b=(b<<6)+m.indexOf(v); l+=6;
    return l<8?'':'%'+(0x100+((b>>>(l-=8))&0xff)).toString(16).slice(-2);
  }));
}

Ahora llamando decode_base64('4pyTIMOgIGxhIG1vZGU=') devolverá la cadena codificada '✓ à la mode', sin errores.

Dado que ‘=’ está reservado como carácter de relleno, puedo reducir mi handicap de golf de código, si puedo:

function decode_base64(s) {
  var b=l=0,
  m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
  return decodeURIComponent(s.replace(/./g, function (v) {
    b=(b<<6)+m.indexOf(v); l+=6;
    return l<8||'='==v?'':'%'+(0x100+((b>>>(l-=8))&0xff)).toString(16).slice(-2);
  }));
}

nJoy!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

MS Access: descripción general

bHumb8ftZNdvsPvfvNiMBS 1200 80

¿Sucederá Scott Pilgrim 2? Edgar Wright revela que hay «algunos planes para revisar el material»