Después de leer el wiki de base64 ...
Estoy tratando de averiguar cómo funciona la fórmula:
Dada una cadena con una longitud de n
, la longitud base64 será
Cual es : 4*Math.Ceiling(((double)s.Length/3)))
Ya sé que la longitud base64 debe ser %4==0
para permitir que el decodificador sepa cuál era la longitud del texto original.
El número máximo de relleno para una secuencia puede ser =
o ==
.
wiki: el número de bytes de salida por byte de entrada es aproximadamente 4/3 (33% de sobrecarga)
Pregunta:
¿ Cómo se establece la información anterior con la longitud de salida ?
4 * n / 3
da longitud sin relleno.Y redondee al múltiplo de 4 más cercano para el relleno, y como 4 es una potencia de 2, puede usar operaciones lógicas bit a bit.
fuente
$(( ((4 * n / 3) + 3) & ~3 ))
4 * n / 3
ya falla enn = 1
, un byte está codificado con dos caracteres, y el resultado es claramente un carácter.Como referencia, la fórmula de longitud del codificador Base64 es la siguiente:
Como dijiste, un codificador Base64 dado
n
bytes de datos producirá una cadena de4n/3
caracteres Base64. Dicho de otra manera, cada 3 bytes de datos generarán 4 caracteres Base64. EDITAR : un comentario señala correctamente que mi gráfico anterior no tenía en cuenta el relleno; La fórmula correcta esCeiling(4n/3)
.El artículo de Wikipedia muestra exactamente cómo la cadena ASCII
Man
codificó en la cadena Base64TWFu
en su ejemplo. La cadena de entrada es de 3 bytes o 24 bits, en tamaño, por lo que la fórmula predice correctamente la salida será de 4 bytes (o 32 bits) de largo:TWFu
. El proceso codifica cada 6 bits de datos en uno de los 64 caracteres Base64, por lo que la entrada de 24 bits dividida por 6 da como resultado 4 caracteres Base64.Usted pregunta en un comentario cuál sería el tamaño de la codificación
123456
. Teniendo en cuenta que cada carácter de esa cadena tiene 1 byte u 8 bits de tamaño (suponiendo la codificación ASCII / UTF8), estamos codificando 6 bytes, o 48 bits, de datos. De acuerdo con la ecuación, esperamos que la longitud de salida sea(6 bytes / 3 bytes) * 4 characters = 8 characters
.La creación de
123456
un codificador Base64 creaMTIzNDU2
, que tiene 8 caracteres de longitud, tal como esperábamos.fuente
floor((3 * (length - padding)) / 4)
. Echa un vistazo a la siguiente esencia .Enteros
Generalmente no queremos usar dobles porque no queremos usar operaciones de coma flotante, errores de redondeo, etc. Simplemente no son necesarios.
Para esto, es una buena idea recordar cómo realizar la división del techo:
ceil(x / y)
en dobles se puede escribir como(x + y - 1) / y
(evitando números negativos, pero tenga cuidado con el desbordamiento).Legible
Si opta por la legibilidad, por supuesto, también puede programarlo de esta manera (por ejemplo, en Java, para C podría usar macros, por supuesto):
En línea
Acolchado
Sabemos que necesitamos bloques de 4 caracteres a la vez por cada 3 bytes (o menos). Entonces la fórmula se convierte (para x = ny e = 3):
o combinado:
su compilador optimizará el
3 - 1
, así que déjelo así para mantener la legibilidad.Sin relleno
Menos común es la variante sin relleno, para esto recordamos que cada uno necesitamos un carácter para cada 6 bits, redondeado:
o combinado:
sin embargo, aún podemos dividir por dos (si queremos):
Ilegible
En caso de que no confíe en su compilador para hacer las optimizaciones finales por usted (o si quiere confundir a sus colegas):
Acolchado
Sin relleno
Así que ahí estamos, dos formas lógicas de cálculo, y no necesitamos ninguna rama, bit-ops u modulo ops, a menos que realmente lo queramos.
Notas:
fuente
Creo que las respuestas dadas pierden el punto de la pregunta original, que es cuánto espacio debe asignarse para ajustarse a la codificación base64 para una cadena binaria dada de longitud n bytes.
La respuesta es
(floor(n / 3) + 1) * 4 + 1
Esto incluye relleno y un carácter nulo de terminación. Es posible que no necesite la llamada de piso si está haciendo aritmética de enteros.
Incluyendo el relleno, una cadena base64 requiere cuatro bytes por cada fragmento de tres bytes de la cadena original, incluidos los fragmentos parciales. Uno o dos bytes adicionales al final de la cadena aún se convertirán a cuatro bytes en la cadena base64 cuando se agregue relleno. A menos que tenga un uso muy específico, es mejor agregar el relleno, generalmente un carácter igual. Agregué un byte adicional para un carácter nulo en C, porque las cadenas ASCII sin esto son un poco peligrosas y tendrías que llevar la longitud de la cadena por separado.
fuente
Aquí hay una función para calcular el tamaño original de un archivo Base 64 codificado como una Cadena en KB:
fuente
Mientras que todos los demás están debatiendo fórmulas algebraicas, prefiero usar BASE64 para decirme:
525
710
Entonces parece que la fórmula de 3 bytes representados por 4 caracteres base64 parece correcta.
fuente
(En un intento de dar una derivación sucinta pero completa).
Cada byte de entrada tiene 8 bits, por lo que para n bytes de entrada obtenemos:
Cada 6 bits es un byte de salida, entonces:
Esto es sin relleno.
Con el relleno, redondeamos eso a múltiples de cuatro bytes de salida:
Ver Divisiones anidadas (Wikipedia) para la primera equivalencia.
Usando aritmética de enteros, ceil ( n / m ) se puede calcular como ( n + m - 1) div m , por lo tanto obtenemos:
Por ilustracion:
Finalmente, en el caso de la codificación MIME Base64, se necesitan dos bytes adicionales (CR LF) por cada 76 bytes de salida, redondeados hacia arriba o hacia abajo dependiendo de si se requiere una nueva línea de terminación.
fuente
Me parece que la fórmula correcta debería ser:
fuente
Creo que esta es una respuesta exacta si n% 3 no es cero, ¿no?
Versión de Mathematica:
Que te diviertas
soldado americano
fuente
Implementación simple en javascript
fuente
Para todas las personas que hablan C, eche un vistazo a estas dos macros:
Tomado de aquí .
fuente
No veo la fórmula simplificada en otras respuestas. La lógica está cubierta pero quería una forma más básica para mi uso incrustado:
NOTA: Al calcular el recuento sin relleno, redondeamos la división entera, es decir, agregamos Divisor-1, que es +2 en este caso
fuente
En Windows, quería estimar el tamaño del búfer de tamaño mime64, pero todas las fórmulas de cálculo precisas no funcionaron para mí, finalmente terminé con una fórmula aproximada como esta:
Tamaño de asignación de cadena de Mine64 (aproximado) = (((4 * ((tamaño del búfer binario) + 1)) / 3) + 1)
Así que el último +1 - se usa para ascii-cero - el último carácter debe asignarse para almacenar la terminación cero - pero ¿por qué el "tamaño del búfer binario" es + 1? Sospecho que hay algún carácter de terminación mime64? O puede ser este es un problema de alineación.
fuente
Si hay alguien interesado en lograr la solución @Pedro Silva en JS, acabo de portar esta misma solución:
fuente