簡體   English   中英

如何在Java中壓縮String?

[英]How to compress a String in Java?

我使用GZIPOutputStreamZIPOutputStream來壓縮String(我的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));
    }
}

結果是:

替代文字

壓縮算法幾乎總是具有某種形式的空間開銷,這意味着它們僅在壓縮數據時有效,該數據足夠大以至於開銷小於節省的空間量。

壓縮一個只有20個字符長的字符串並不容易,但並不總是可行。 如果你有重復,霍夫曼編碼或簡單的游程編碼可能能夠壓縮,但可能不是很多。

創建String時,可以將其視為char的列表,這意味着對於String中的每個字符,您需要支持char的所有可能值。 來自太陽博士

char :char數據類型是一個16位Unicode字符。 它的最小值為'\\ u0000'(或0),最大值為'\\ uffff'(或65,535(含))。

如果你想要支持一組簡化的字符,你可以編寫一個簡單的壓縮算法,類似於binary-> decimal-> hex radix converstion。 您從65,536(或目標系統支持的多個字符)到26(字母)/ 36(字母數字)等。

我曾經多次使用過這個技巧,例如將時間戳編碼為文本(目標36 +,源10) - 只需確保你有足夠的單元測試!

如果密碼或多或少“隨機”,那么你運氣不好,你將無法大幅減少尺寸。

但是:為什么需要壓縮密碼? 也許你需要的不是壓縮,而是某種哈希值? 如果您只需要檢查名稱是否與給定密碼匹配,則不需要保存密碼,但可以保存密碼的哈希值。 要檢查鍵入的密碼是否與給定名稱匹配,您可以采用相同的方式構建哈希值,並將其與保存的哈希值進行比較。 由於散列(Object.hashCode())是一個int,您將能夠以80個字節存儲所有20個密碼哈希值。

你的朋友是對的。 gzip和ZIP都基於DEFLATE 這是一種通用算法,不適用於編碼小字符串。

如果需要,可能的解決方案是自定義編碼和解碼HashMap<String, String> 這可以讓您進行簡單的一對一映射:

HashMap<String, String> toCompressed, toUncompressed;

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

顯然,這需要設置,並且僅適用於少量字符串。

霍夫曼編碼可能有所幫助,但前提是你的小字符串中有很多頻繁的字符

ZIP算法是LZWHuffman Trees的組合。 您可以單獨使用這些算法之一。

壓縮基於2個因素:

  • 原始鏈中的子串的重復(LZW):如果有很多重復,壓縮將是有效的。 該算法具有良好的壓縮長文本的性能,因為經常重復單詞
  • 壓縮鏈中每個字符的數量(Huffman):字符之間的重新分配越多,壓縮就越有效

在您的情況下,您應該只嘗試LZW算法。 基本上使用,鏈可以在不添加元信息的情況下進行壓縮:對於短字符串壓縮,它可能更好。

對於霍夫曼算法,編碼樹必須與壓縮文本一起發送。 因此,對於小文本,由於樹,結果可能比原始文本大。

霍夫曼編碼是一個明智的選擇。 Gzip和朋友這樣做,但他們的工作方式是為輸入構建一個Huffman樹,發送它,然后發送用樹編碼的數據。 如果樹相對於數據較大,則可能沒有節省大小。

但是,可以避免發送樹:相反,您安排發送方和接收方已經擁有樹。 它不能專門為每個字符串構建,但您可以使用一個全局樹來編碼所有字符串。 如果你使用與輸入字符串(英語或其他)相同的語言構建它,你仍然應該獲得良好的壓縮,盡管不如每個輸入的自定義樹一樣好。

如果您知道您的字符串主要是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);

看看Huffman算法。

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

這個想法是每個字符都被比特序列替換,取決於它們在文本中的頻率(頻率越高,序列越小)。

您可以閱讀整個文本並構建代碼表,例如:

符號代碼

一個0

10

e 110

m 111

該算法基於文本輸入構建符號樹。 你擁有的角色種類越多,壓縮效果就越差。

但根據你的文字,它可能是有效的。

您沒有看到您的String發生任何壓縮,因為您至少需要幾百個字節才能使用GZIPOutputStream或ZIPOutputStream進行實際壓縮。 你的字符串太小了。(我不明白為什么你需要壓縮)

查看本文的結論:

本文還介紹了如何動態壓縮和解壓縮數據,以減少網絡流量並提高客戶端/服務器應用程序的性能。 但是,只有當被壓縮的對象超過幾百個字節時,動態壓縮數據才能提高客戶端/服務器應用程序的性能。 例如,如果被壓縮和傳輸的對象是簡單的String對象,則無法觀察到性能的提高。

Java 9中提供了緊湊的字符串增強功能https://openjdk.java.net/jeps/254

java.lang.String現在有:

private final byte [] value;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM