2011-03-20 9 views
6

Esta función de JavaScript toma una matriz de números (en el rango 0-255) y convierte a una cadena codificada en base64, luego se rompe líneas si es necesario:Convertir matriz de valores de bytes a cadena codificada en base64 y romper líneas largas, Javascript (código de golf)

function encode(data) 
{ 
    var str = ""; 
    for (var i = 0; i < data.length; i++) 
    str += String.fromCharCode(data[i]); 

    return btoa(str).split(/(.{75})/).join("\n").replace(/\n+/g, "\n").trim(); 
} 

¿Se puede hacer lo mismo con menos código? ¿Puedes hacerlo para que funcione más rápido? La portabilidad no tiene objeto, utilice nuevas funciones de idioma si lo desea, pero debe estar en JavaScript.

+0

corre más rápido en el navegador (s)? 'btoa' solo es compatible con los navegadores Gecko y WebKit hasta donde yo sé. – Gabe

+0

Da la casualidad que se trata de una pieza muy pequeña de una extensión de Firefox, pero si tienes una forma inteligente de hacerlo utilizando el JS de otros navegadores, me alegra ver eso también. – zwol

+0

ahem ... http://codegolf.stackexchange.com/ – jessegavin

Respuesta

13

tengo otra entrada:

function encode(data) 
{ 
    var str = String.fromCharCode.apply(null,data); 
    return btoa(str).replace(/.{76}(?=.)/g,'$&\n'); 
} 

Minificado, 88 caracteres:

function e(d){return btoa(String.fromCharCode.apply(d,d)).replace(/.{76}(?=.)/g,'$&\n')} 

O si quieres saltos de línea finales, 85 caracteres:

function e(d){return btoa(String.fromCharCode.apply(d,d)).replace(/.{1,76}/g,'$&\n')} 
+1

¡Oh, muy agradable! Aunque no estoy 100% seguro sobre el uso de 'apply'. Hay un límite estricto de algo así como 2 ** 19 argumentos para cualquier función (en Firefox, de todos modos) y creo que podría tener que hacer más que un poco más de trabajo desempaquetar la matriz en el área de argumentos. No espero que mis arreglos sean * * largo, sin embargo, y la brevedad es agradable. – zwol

+0

Lo probé hace un momento (en Firebug), trabajó hasta aproximadamente 12 * 2 ** 20 números aquí. Y ese no era ni siquiera un límite, solo informaba que la cuota de espacio de pila de scripts se había agotado. – Anomie

+0

¿Cuánto tiempo lleva? ¿Puedes medir nuestros diversos métodos con matrices de bytes grandes? – Gabe

2

funciona en Firefox 3.6.13:

function encode(data) 
{ 
    var str = data.reduce(function(a,b){ return a+String.fromCharCode(b) },''); 
    return btoa(str).replace(/.{76}(?=.)/g,'$&\n'); 
} 
+0

¿Necesitas ese 'trim' ahí? – Gabe

+0

@Gabe: Lo puse para evitar que la cadena devuelta tenga un linebreak que se arrastra cuando la cadena codificada en base64 es un múltiplo exacto de la longitud de línea mientras que si no tiene el salto de línea. Pero cuando escribí eso en respuesta a ti, pensé: "¿El motor javascript regex de Firefox admite una apariencia positiva de ancho cero?". Y lo hace! Editado – Anomie

+0

Oh, es el objeto aquí los caracteres mínimos? Esto se puede minimizar a 116 caracteres, o 113 si desea que cada salida tenga una nueva línea final (cambie la expresión regular a '/. {1,76}/g'). – Anomie

1

no tengo Firefox a mano, así que no puedo probarlo, pero desde una perspectiva general de manejo de series que parece que tiene algo de espacio mejorar. Lo que estás haciendo es, por cada byte, crear una nueva cadena de un carácter más larga que la anterior. Esta es una operación O (N^2). Hay algunas maneras de reducir N para que su algoritmo se ejecuta en casi lineal tiempo:

  1. Build hasta cadenas a la longitud 57 (esto va a dar un resultado 76-char base 64), a continuación, realizar una btoa en y añada la cadena resultante a su resultado

  2. Al igual que en el n. ° 1, solo cree un conjunto de líneas y llame al join para crear la cadena final de salida.

  3. Utilice map para crear una matriz de cadenas de 1 carácter, luego llame al join en él.

Aquí hay un código no probado para cada método:

function encode(data) 
{ 
    var output = ""; 
    var str = ""; 
    for (var i = 0; i < data.length; i++) 
    { 
    str += String.fromCharCode(data[i]); 
    // the "&& i != data.length - 1" clause 
    // keeps the extra \n off the end of the output 
    // when the last line is exactly 76 characters 
    if (str.length == 57 && i != data.length - 1) 
    { 
     output += btoa(str) + "\n"; 
     str = ""; 
    } 
    } 
    return output + btoa(str); 
} 

function encode(data) 
{ 
    var output = []; 
    var str = ""; 
    for (var i = 0; i < data.length; i++) 
    { 
    str += String.fromCharCode(data[i]); 
    if (str.length == 57) 
    { 
     output[output.length] = btoa(str); 
     str = ""; 
    } 
    } 
    if (str != "") 
    output[output.length] = btoa(str); 
    return output.join("\n"); 
} 

function encode(data) 
{ 
    var str = data.map(function (d) { return String.fromCharCode(d) }).join(""); 
    return btoa(str).replace(/.{76}(?=.)/g,'$&\n'); 
} 

Y aquí es la última, minified (116 caracteres):

function e(b){return btoa(b.map(function(d){return 
String.fromCharCode(d)}).join("")).replace(/.{76}(?=.)/g,'$&\n')} 
+0

Se requiere un cierre, porque el mapa invoca su función con 3 argumentos (elemento de matriz, índice y el objeto de matriz) y String.fromCharCode puede tomar múltiples puntos de código como argumentos para devolver una cadena de caracteres múltiples. Casualmente, recordé esto justo antes de publicar y me di cuenta de que podía aprovechar ese hecho. – Anomie

+0

Me gusta la idea de dividir 57 bytes a la vez para alimentar a 'btoa'. – zwol

Cuestiones relacionadas