Cómo comprimir una cadena en Java?

Yo uso GZIPOutputStream o ZIPOutputStream para comprimir un String (mi string.length() es menor que 20), pero el resultado comprimido es más largo que el de la cadena original.

En algún sitio, encontré que algunos amigos dijeron que esto se debe a que mi cadena original es demasiado corta, GZIPOutputStream puede usarse para comprimir cadenas más largas.

Entonces, ¿alguien me puede ayudar 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 :

texto alternativo

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 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 encoding de Huffman o la encoding simple de longitud de ejecución podrían ser capaces de comprimir, pero probablemente no mucho.

Cuando creas un String, puedes pensar que es una lista de char, esto significa que para cada personaje de tu String, necesitas admitir todos los valores posibles de char. De los doctores del sol

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 binario-> decimal-> hexagix. Pasas de 65.536 (o cuantos caracteres admite tu sistema objective) a 26 (alfabético) / 36 (alfanumérico), etc.

He usado este truco varias veces, por ejemplo, codificando marcas de tiempo como texto (objective 36 +, fuente 10) – ¡solo asegúrate de tener suficientes pruebas unitarias!

Si las contraseñas son más o menos “aleatorias”, no tiene suerte, no podrá obtener una reducción significativa de tamaño.

Pero: ¿Por qué necesitas comprimir las contraseñas? Tal vez lo que necesita no es una compresión, ¿pero algún tipo de valor hash? Si solo necesita comprobar si un nombre coincide con una contraseña determinada, no es necesario 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 construir el valor hash de la misma manera y compararlo con el hash guardado. Como un hash (Object.hashCode ()) es un int, podrá almacenar los 20 contraseñas de contraseña en 80 bytes.

Tu amigo es correcto Tanto gzip como ZIP están basados ​​en DEFLATE . Este es un algoritmo de propósito general, y no está destinado a la encoding de cadenas pequeñas.

Si necesita esto, una posible solución es una encoding y desencoding personalizada HashMap . Esto puede permitirle realizar un mapeo sencillo de uno a uno:

 HashMap toCompressed, toUncompressed; String compressed = toCompressed.get(uncompressed); // ... String uncompressed = toUncompressed.get(compressed); 

Claramente, esto requiere configuración, y solo es práctico para una pequeña cantidad de cadenas.

La encoding de Huffman podría ayudar, pero solo si tienes muchos caracteres frecuentes en tu pequeña cadena

El algoritmo ZIP es una combinación de LZW y Huffman Trees . Puede usar 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 un buen rendimiento para comprimir un texto plano largo, ya que las palabras se repiten a menudo
  • el número de cada personaje en la cadena comprimida (Huffman): más desequilibrado que el reparto entre los personajes, más la compresión será eficiente

En su caso, debe probar el algoritmo LZW solamente. Utilizado 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 encoding debe enviarse con el texto comprimido. Entonces, para un texto pequeño, el resultado puede ser más grande que el texto original, debido al árbol.

La encoding de 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 haya ningún tamaño de almacenamiento.

Sin embargo, es posible evitar el envío de un árbol: en su lugar, acuerda que el emisor y el receptor ya tengan uno. No se puede crear específicamente para cada cadena, pero puede tener un solo árbol global utilizado para codificar todas las cadenas. Si lo construye desde el mismo idioma que las cadenas de entrada (en inglés o lo que sea), aún así debe obtener una buena compresión, aunque no tan buena como con un árbol personalizado para cada entrada.

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 convertir de nuevo a una cadena:

 private final Charset UTF8_CHARSET = Charset.forName("UTF-8"); ... String s = new String(bytes, UTF8_CHARSET); 

No ve que se produzca ninguna compresión para su String, ya que al menos requiere unos cientos de bytes para tener una compresión real usando GZIPOutputStream o ZIPOutputStream. Su cadena es demasiado pequeña. (No entiendo por qué necesita compresión para el mismo)

Verifique la conclusión de este artículo :

El artículo también muestra cómo comprimir y descomprimir datos sobre la marcha para reducir el tráfico de red y mejorar el rendimiento de las aplicaciones de cliente / servidor. La compresión de datos sobre la marcha, sin embargo, mejora el rendimiento de las aplicaciones cliente / servidor solo cuando los objetos que se están comprimiendo tienen más de un par de cientos de bytes. No podrá observar una mejora en el rendimiento si los objetos comprimidos y transferidos son simples objetos String, por ejemplo.

Eche un vistazo al algoritmo de Huffman.

https://codereview.stackexchange.com/questions/44473/huffman-code-implementation

La idea es que cada personaje sea reemplazado con 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

a 0

s 10

e 110

m 111

El algoritmo crea un árbol de símbolos basado en la entrada de texto. Cuanta más variedad de caracteres tenga, peor será la compresión.

Pero dependiendo de tu texto, podría ser efectivo.