java - 在 Java 中缩短已经很短的字符串

标签 java string encoding compression

我正在寻找一种方法来尽可能缩短已经很短的字符串。

该字符串是主机名:端口组合,可能类似于“my-domain.se:2121”或“123.211.80.4:2122”。

我知道常规压缩对于这么短的字符串来说几乎是不可能的,因为需要开销并且没有重复,但我知道如何去做。

因为字母表限制为 39 个字符 ([a-z][0-9]-:.),所以每个字符都可以放入 6 位中。与 ASCII 相比,这最多可减少 25% 的长度。所以我的建议是这样的:

  1. 使用某种自定义编码将字符串编码为字节数组
  2. 将字节数组解码为 UTF-8 或 ASCII 字符串(该字符串显然没有任何意义)。

再逆向得到原始字符串。

所以我的问题是:

  1. 这行得通吗?
  2. 有没有更好的方法?
  3. 如何?

最佳答案

您可以将字符串编码为 base 40,它比 base 64 更紧凑。这将为您提供 12 个这样的标记到 64 位长。第 40 个标记可能是字符串标记的结尾,以提供长度(因为它不再是整数字节)

如果您使用算术编码,它可能会小得多,但您需要每个标记的频率表。 (使用一长串可能的例子)

class Encoder {
  public static final int BASE = 40;
  StringBuilder chars = new StringBuilder(BASE);
  byte[] index = new byte[256];

  {
    chars.append('\0');
    for (char ch = 'a'; ch <= 'z'; ch++) chars.append(ch);
    for (char ch = '0'; ch <= '9'; ch++) chars.append(ch);
    chars.append("-:.");
    Arrays.fill(index, (byte) -1);
    for (byte i = 0; i < chars.length(); i++)
      index[chars.charAt(i)] = i;
  }

  public byte[] encode(String address) {
    try {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      DataOutputStream dos = new DataOutputStream(baos);
      for (int i = 0; i < address.length(); i += 3) {
        switch (Math.min(3, address.length() - i)) {
          case 1: // last one.
            byte b = index[address.charAt(i)];
            dos.writeByte(b);
            break;

          case 2:
            char ch = (char) ((index[address.charAt(i+1)]) * 40 + index[address.charAt(i)]);
            dos.writeChar(ch);
            break;

          case 3:
            char ch2 = (char) ((index[address.charAt(i+2)] * 40 + index[address.charAt(i + 1)]) * 40 + index[address.charAt(i)]);
            dos.writeChar(ch2);
            break;
        }
      }
      return baos.toByteArray();
    } catch (IOException e) {
      throw new AssertionError(e);
    }
  }

  public static void main(String[] args) {
    Encoder encoder = new Encoder();
    for (String s : "twitter.com:2122,123.211.80.4:2122,my-domain.se:2121,www.stackoverflow.com:80".split(",")) {
      System.out.println(s + " (" + s.length() + " chars) encoded is " + encoder.encode(s).length + " bytes.");
    }
  }
}

打印

twitter.com:2122 (16 chars) encoded is 11 bytes.
123.211.80.4:2122 (17 chars) encoded is 12 bytes.
my-domain.se:2121 (17 chars) encoded is 12 bytes.
www.stackoverflow.com:80 (24 chars) encoded is 16 bytes.

我把解码留作练习。 ;)

关于java - 在 Java 中缩短已经很短的字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7389252/

相关文章:

java - 方向更改崩溃后替换 fragment

java - 在 Grails (Groovy) 和 Java 类之间传递域类的最佳实践?

encoding - Google Fusion Tables cvs上传编码问题

php - Laravel 与 ioncube 和编码

text - 这个二进制字符串是什么编码?

Java:如何绑定(bind)两个不同数组的值

JAVAFX:从数据库加载图像

android - 在 Android 中检查空电子邮件字符串时出错

asp.net - 文件名包含空格的 TransmitFile

java - 从字符串中提取目录