funciones - ¿Cómo comprimir una cadena en Java?
java gzip decompress (10)
Cuando creas una Cadena, puedes verla como una lista de caracteres, esto significa que para cada personaje de tu Cadena, necesitas apoyar todos los valores posibles de caracteres. Desde el sol docs
char : El tipo de datos char es un único carácter Unicode de 16 bits. Tiene un valor mínimo de ''/ u0000'' (o 0) y un valor máximo de ''/ uffff'' (o 65,535 inclusive).
Si tiene un conjunto reducido de caracteres que desea admitir, puede escribir un algoritmo de compresión simple, que es análogo a la conversión de binario-> decimal-> hexadecimal. Pasa de 65.536 (o de todos los caracteres que admita su sistema de destino) a 26 (alfabético) / 36 (alfanumérico) etc.
He usado este truco varias veces, por ejemplo, codificando marcas de tiempo como texto (target 36+, fuente 10). ¡Solo asegúrate de que tienes un montón de pruebas de unidad!
Utilizo GZIPOutputStream
o ZIPOutputStream
para comprimir una cadena (mi string.length()
es menor que 20), pero el resultado comprimido es más largo que la cadena original.
En algún sitio, encontré que algunos amigos dijeron que esto se debe a que mi cadena original es demasiado corta, se puede usar GZIPOutputStream
para comprimir cadenas más largas.
Entonces, ¿alguien puede ayudarme a comprimir una cadena?
Mi función es como:
String compress(String original) throws Exception {
}
Actualizar:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import java.util.zip.*;
//ZipUtil
public class ZipUtil {
public static String compress(String str) {
if (str == null || str.length() == 0) {
return str;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPOutputStream gzip = new GZIPOutputStream(out);
gzip.write(str.getBytes());
gzip.close();
return out.toString("ISO-8859-1");
}
public static void main(String[] args) throws IOException {
String string = "admin";
System.out.println("after compress:");
System.out.println(ZipUtil.compress(string));
}
}
El resultado es :
Echa un vistazo al algoritmo de Huffman.
https://codereview.stackexchange.com/questions/44473/huffman-code-implementation
La idea es que cada carácter sea reemplazado por una secuencia de bits, dependiendo de su frecuencia en el texto (cuanto más frecuente, más pequeña es la secuencia).
Puede leer todo el texto y crear una tabla de códigos, por ejemplo:
Código de símbolo
un 0
s 10
e 110
m 111
El algoritmo construye un árbol de símbolos basado en la entrada de texto. Cuanta más variedad de caracteres tengas, peor será la compresión.
Pero dependiendo de tu texto, podría ser efectivo.
El algoritmo ZIP es una combinación de LZW y Huffman Trees . Puede utilizar uno de estos algoritmos por separado.
La compresión se basa en 2 factores:
- la repetición de subcadenas en su cadena original (LZW): si hay muchas repeticiones, la compresión será eficiente. Este algoritmo tiene buenos rendimientos para comprimir un texto plano largo, ya que las palabras a menudo se repiten
- el número de cada carácter en la cadena comprimida (Huffman): más la repartición entre los caracteres no está equilibrada, más la compresión será eficiente
En su caso, debe probar el algoritmo LZW solamente. Básicamente, la cadena se puede comprimir sin agregar metainformaciones: probablemente sea mejor para la compresión de cadenas cortas.
Para el algoritmo de Huffman, el árbol de codificación debe enviarse con el texto comprimido. Por lo tanto, para un texto pequeño, el resultado puede ser más grande que el texto original, debido al árbol.
La codificación Huffman es una opción sensata aquí. Gzip y sus amigos hacen esto, pero la forma en que trabajan es construir un árbol Huffman para la entrada, enviar eso y luego enviar los datos codificados con el árbol. Si el árbol es grande en relación con los datos, es posible que no se guarde el tamaño.
Sin embargo, es posible evitar enviar un árbol: en lugar de eso, usted hace que el remitente y el destinatario ya tengan uno. No se puede crear específicamente para cada cadena, pero puede tener un solo árbol global para codificar todas las cadenas. Si lo creas desde el mismo idioma que las cadenas de entrada (en inglés o lo que sea), todavía deberías obtener una buena compresión, aunque no tanto como con un árbol personalizado para cada entrada.
Los algoritmos de compresión casi siempre tienen algún tipo de sobrecarga de espacio, lo que significa que solo son efectivos cuando se comprimen datos que son lo suficientemente grandes como para que la sobrecarga sea menor que la cantidad de espacio guardado.
Comprimir una cadena de solo 20 caracteres no es demasiado fácil, y no siempre es posible. Si tiene repetición, la codificación Huffman o la codificación simple de longitud de ejecución podrían comprimir, pero probablemente no mucho.
No ve que ocurra ninguna compresión para su String, ya que al menos necesita un par de cientos de bytes para tener una compresión real utilizando GZIPOutputStream o ZIPOutputStream. Su cadena es demasiado pequeña (no entiendo por qué necesita compresión para la misma)
Compruebe la conclusión de este article :
El artículo también muestra cómo comprimir y descomprimir los datos sobre la marcha para reducir el tráfico de red y mejorar el rendimiento de sus aplicaciones cliente / servidor. Sin embargo, la compresión de datos sobre la marcha mejora el rendimiento de las aplicaciones cliente / servidor cuando los objetos comprimidos tienen más de un par de cientos de bytes. No podría observar una mejora en el rendimiento si los objetos comprimidos y transferidos son simples objetos String, por ejemplo.
Si las contraseñas son más o menos "aleatorias", no está de suerte, no podrá obtener una reducción significativa en el tamaño.
Pero: ¿Por qué necesitas comprimir las contraseñas? Tal vez lo que necesita no es una compresión, sino algún tipo de valor hash? Si solo necesita verificar si un nombre coincide con una contraseña dada, no necesita guardar la contraseña, pero puede guardar el hash de una contraseña. Para verificar si una contraseña ingresada coincide con un nombre dado, puede generar el valor de hash de la misma manera y compararlo con el hash guardado. Como un hash (Object.hashCode ()) es un int, podrás almacenar los 20 hashes de contraseña en 80 bytes).
Si sabe que sus cadenas son en su mayoría ASCII, puede convertirlas a UTF-8.
byte[] bytes = string.getBytes("UTF-8");
Esto puede reducir el tamaño de la memoria en aproximadamente un 50%. Sin embargo, obtendrá una matriz de bytes y no una cadena. Sin embargo, si lo está escribiendo en un archivo, eso no debería ser un problema.
Para volver a convertir en una cadena:
private final Charset UTF8_CHARSET = Charset.forName("UTF-8");
...
String s = new String(bytes, UTF8_CHARSET);
Tu amigo tiene razón. Tanto gzip como ZIP están basados en DEFLATE . Este es un algoritmo de propósito general, y no está diseñado para codificar cadenas pequeñas.
Si necesita esto, una posible solución es una codificación y decodificación personalizada HashMap<String, String>
. Esto puede permitirle hacer un mapeo uno a uno simple:
HashMap<String, String> toCompressed, toUncompressed;
String compressed = toCompressed.get(uncompressed);
// ...
String uncompressed = toUncompressed.get(compressed);
Claramente, esto requiere configuración, y solo es práctico para un pequeño número de cadenas.
La codificación Huffman puede ayudar, pero solo si tienes muchos personajes frecuentes en tu cadena pequeña