如何在Java中压缩字符串?
我使用GZIPOutputStream或ZIPOutputStream压缩字符串(我的2222235278130938882小于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));
}
}
结果是:
11个解决方案
38 votes
压缩算法几乎总是具有某种形式的空间开销,这意味着它们仅在压缩足够大以至于开销小于节省的空间量的数据时才有效。
压缩仅20个字符长的字符串并不是一件容易的事,而且并非总是可能的。 如果有重复,霍夫曼编码或简单的行程编码可能可以压缩,但可能压缩得很少。
JesperE answered 2020-01-28T07:13:27Z
9 votes
创建字符串时,可以将其视为char的列表,这意味着对于String中的每个字符,您需要支持char的所有可能值。 来自太阳的文档
char:char数据类型是单个16位Unicode字符。 它的最小值为'\ u0000'(或0),最大值为'\ uffff'(或65,535(含))。
如果要支持的字符集减少了,可以编写一个简单的压缩算法,类似于二进制->小数->十六进制基数转换。 您从65,536(或目标系统支持的许多字符)到26(字母)/ 36(字母数字)等。
我已经使用过几次这个技巧,例如将时间戳记编码为文本(目标36 +,源10)-请确保您有足够的单元测试!
Jon Freedman answered 2020-01-28T07:14:02Z
8 votes
如果密码或多或少是“随机的”,那么您就不走运了,您将无法大幅度减小密码的大小。
但是:为什么您需要压缩密码? 也许您需要的不是压缩,而是某种哈希值? 如果仅需要检查名称是否与给定密码匹配,则无需保存密码,但可以保存密码的哈希值。 要检查键入的密码是否与给定名称匹配,您可以用相同的方式构建哈希值,并将其与保存的哈希值进行比较。 由于哈希(Object.hashCode())是一个int,您将能够以80个字节存储所有20个密码哈希)。
Arne Deutsch answered 2020-01-28T07:14:28Z
6 votes
你的朋友是正确的。 gzip和ZIP均基于DEFLATE。 这是一种通用算法,并不旨在编码小字符串。
如果需要,可能的解决方案是自定义编码和解码HashMap。这可以让您进行简单的一对一映射:
HashMap toCompressed, toUncompressed;
String compressed = toCompressed.get(uncompressed);
// ...
String uncompressed = toUncompressed.get(compressed);
显然,这需要进行设置,并且仅适用于少量的字符串。
Matthew Flaschen answered 2020-01-28T07:14:57Z
4 votes
霍夫曼编码可能会有所帮助,但前提是您的小字符串中有很多常用字符
Noel M answered 2020-01-28T07:15:18Z
4 votes
ZIP算法是LZW和霍夫曼树的组合。 您可以单独使用这些算法之一。
压缩基于两个因素:
原始链(LZW)中子字符串的重复:如果重复很多,压缩将非常有效。 该算法具有压缩长文本的良好性能,因为单词经常被重复
压缩链中每个字符的数量(霍夫曼):字符之间的重分配越不平衡,压缩效率越高
在您的情况下,您应该只尝试LZW算法。 基本上可以使用此链,而无需添加元信息即可对其进行压缩:对于短字符串压缩而言,它可能会更好。
对于霍夫曼算法,编码树必须与压缩文本一起发送。 因此,由于树的缘故,对于小的文本,结果可能大于原始文本。
Benoit Courtine answered 2020-01-28T07:16:01Z
4 votes
在此,霍夫曼编码是一个明智的选择。 Gzip和朋友可以这样做,但是他们的工作方式是为输入构建霍夫曼树,发送该树,然后发送使用该树编码的数据。 如果树相对于数据而言较大,则可能不会不节省任何大小。
但是,可以避免发送一棵树:相反,您安排发送者和接收者已经有一棵树。 并不是专门针对每个字符串构建的,但是您可以使用一个全局树来编码所有字符串。 如果您使用与输入字符串相同的语言(英语或其他语言)来构建它,则尽管每个输入的自定义树效果都不如自定义树,但仍应获得良好的压缩效果。
Tom Anderson answered 2020-01-28T07:16:28Z
2 votes
如果您知道您的字符串主要是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);
rghome answered 2020-01-28T07:17:03Z
0 votes
您没有看到String发生任何压缩,因为您至少需要数百个字节才能使用GZIPOutputStream或ZIPOutputStream进行真正的压缩。 您的字符串太小。(我不明白为什么您需要对其进行压缩)
检查本文的结论:
本文还展示了如何压缩 并即时解压缩数据 为了减少网络流量和 改善您的表现 客户端/服务器应用程序。 即时压缩数据, 提高性能 客户端/服务器应用程序仅在 被压缩的对象更多 超过几百个字节。 您 将无法观察 如果性能改善 对象被压缩 传输的是简单的String对象, 例如。
YoK answered 2020-01-28T07:17:34Z
0 votes
看看霍夫曼算法。
[https://codereview.stackexchange.com/questions/44473/huffman-code-implementation]
想法是,每个字符都将替换为位序列,具体取决于它们在文本中的出现频率(频率越高,序列越小)。
您可以阅读全文并建立一个代码表,例如:
代号
0
s 10
e 110
m 111
该算法基于文本输入构建符号树。 字符种类越多,压缩效果越差。
但是,取决于您的文字,它可能是有效的。
live-love answered 2020-01-28T07:18:38Z
0 votes
Java 9可直接使用紧凑的字符串增强功能[https://openjdk.java.net/jeps/254]
java.lang.String现在具有:
私有最终字节[]值;
Anurag Sharma answered 2020-01-28T07:19:06Z