it-swarm.com.ru

Как сжать строку в Java?

Я использую GZIPOutputStream или ZIPOutputStream для сжатия строки (моя string.length() меньше 20), но сжатый результат длиннее исходной строки.

На каком-то сайте я обнаружил, что некоторые друзья говорили, что это потому, что моя исходная строка слишком короткая, GZIPOutputStream может использоваться для сжатия более длинных строк.

итак, кто-нибудь может мне помочь сжать строку?

Моя функция похожа на:

String compress(String original) throws Exception {

}

Обновление:

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));
    }
}

Результат:

alt text

48
user421851

Алгоритмы сжатия почти всегда имеют некоторую форму пространственных накладных расходов, что означает, что они эффективны только при сжатии данных, которые достаточно велики, чтобы накладные расходы были меньше, чем объем сэкономленного пространства.

Сжать строку длиной всего 20 символов не так просто, и это не всегда возможно. Если у вас есть повторение, кодирование Хаффмана или простое кодирование длин серий может сжимать, но, вероятно, не очень.

36
JesperE

Когда вы создаете строку, вы можете думать о ней как о списке символов, это означает, что для каждого символа в вашей строке вам необходимо поддерживать все возможные значения символа. От Солнца документы

char: тип данных char представляет собой один 16-битный символ Unicode. Он имеет минимальное значение «\ u0000» (или 0) и максимальное значение «\ uffff» (или 65 535 включительно). 

Если у вас есть сокращенный набор символов, которые вы хотите поддерживать, вы можете написать простой алгоритм сжатия, который аналогичен двоичному -> десятичному -> шестнадцатеричному разговору. Вы переходите с 65 536 (или любого количества символов, поддерживаемых вашей целевой системой) на 26 (в алфавитном порядке)/36 (в буквенно-цифровом формате) и т.д.

Я использовал этот прием несколько раз, например, для кодирования временных меток в виде текста (цель 36+, источник 10) - просто убедитесь, что у вас достаточно юнит-тестов!

9
Jon Freedman

Если пароли более или менее «случайны», вам не повезло, вы не сможете получить значительное уменьшение в размере.

Но: Зачем вам нужно сжимать пароли? Может быть, вам нужно не сжатие, а какое-то хеш-значение? Если вам просто нужно проверить, соответствует ли имя заданному паролю, вам не нужно сохранять пароль, но вы можете сохранить хэш пароля. Чтобы проверить, соответствует ли введенный пароль указанному имени, вы можете создать хеш-значение таким же образом и сравнить его с сохраненным хеш-кодом. Поскольку хеш (Object.hashCode ()) является целым числом, вы сможете хранить все 20 хэшей паролей в 80 байтах).

7
Arne Deutsch

Твой друг прав. И gzip, и Zip основаны на DEFLATE . Это алгоритм общего назначения, и он не предназначен для кодирования небольших строк.

Если вам это нужно, возможное решение - настраиваемая кодировка и декодирование HashMap<String, String>. Это может позволить вам сделать простое сопоставление один к одному:

HashMap<String, String> toCompressed, toUncompressed;

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

Понятно, что это требует настройки и является практичным только для небольшого числа строк.

6
Matthew Flaschen

Алгоритм Zip представляет собой комбинацию LZW и Деревья Хаффмана . Вы можете использовать один из этих алгоритмов отдельно.

Сжатие основано на 2 факторах:

  • повторение подстрок в исходной цепочке (LZW): если повторений много, сжатие будет эффективным. Этот алгоритм имеет хорошие характеристики для сжатия длинного простого текста, так как слова часто повторяются
  • количество каждого символа в сжатой цепочке (Хаффман): чем больше неравенство между символами, тем эффективнее будет сжатие

В вашем случае вы должны попробовать только алгоритм LZW. В принципе, цепочка может быть сжата без добавления метаинформации: это, вероятно, лучше для сжатия коротких строк.

Для алгоритма Хаффмана дерево кодирования должно быть отправлено со сжатым текстом. Таким образом, для небольшого текста результат может быть больше исходного текста из-за дерева.

4
Benoit Courtine

Кодировка Хаффмана является разумным вариантом здесь. Gzip и друзья делают это, но они работают, чтобы построить дерево Хаффмана для ввода, отправить его, а затем отправить данные, закодированные с помощью дерева. Если дерево велико по отношению к данным, не может быть никакого сохранения в размере.

Однако можно избежать отправки дерева: вместо этого вы договариваетесь, чтобы отправитель и получатель уже имели его. Он не может быть создан специально для каждой строки, но у вас может быть одно глобальное дерево, используемое для кодирования всех строк. Если вы строите его на том же языке, что и строки ввода (английский или любой другой), вы все равно должны получить хорошее сжатие, хотя и не так хорошо, как с настраиваемым деревом для каждого ввода.

4
Tom Anderson

Huffman Coding может помочь, но только в том случае, если в маленькой строке есть много частых символов

4
Noel M

Если вы знаете, что ваши строки в основном ASCII, вы можете преобразовать их в UTF-8.

byte[] bytes = string.getBytes("UTF-8");

Это может уменьшить объем памяти примерно на 50%. Однако вы получите массив байтов, а не строку. Если вы записываете его в файл, это не должно быть проблемой.

Чтобы преобразовать обратно в строку:

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

Посмотрите на алгоритм Хаффмана.

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

Идея состоит в том, что каждый символ заменяется последовательностью битов, в зависимости от их частоты в тексте (чем чаще, тем меньше последовательность). 

Вы можете прочитать весь текст и создать таблицу кодов, например:

Код символа

0

с 10

е 110

м 111

Алгоритм строит дерево символов на основе ввода текста. Чем больше у вас разнообразных символов, тем хуже будет сжатие.

Но в зависимости от вашего текста, это может быть эффективным. 

0
live-love

Вы не видите никакого сжатия для вашей строки, так как вам требуется, по крайней мере, пара сотен байтов для реального сжатия с использованием GZIPOutputStream или ZIPOutputStream. Ваша строка слишком мала (я не понимаю, почему вы требуете сжатия для того же самого)

Проверьте вывод из этой статьи

В статье также показано, как сжимать и распаковывать данные на лету в чтобы уменьшить сетевой трафик и улучшить производительность вашего клиент-серверные приложения . Сжатие данных на лету, однако улучшает производительность клиент/серверные приложения только когда сжатые объекты больше чем пару сотен байтов. Вы не сможет наблюдать улучшение производительности, если сжатые объекты и переданы простые строковые объекты, например.

0
YoK