有限字符集的字符串压缩算法

这篇具有很好参考价值的文章主要介绍了有限字符集的字符串压缩算法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

在开发中,经常有上报线上堆栈来分析处理线上问题的场景,所以,对堆栈的压缩和加密也是必不可少的。加密:可以使用AES对称加密算法,压缩:可以在上传时利用protobuf天生的压缩性对字符串进行压缩。

不过,出于对流量的节省和传输效率的提升,可以通过在堆栈上传前先压缩一次数据来保证。下面给大家介绍一种笔者自己摸索的一种压缩字符串的算法,并且自带加密效果。

算法介绍

此算法使用场景:有限字符集的字符串压缩。

例如Java方法全限定名的压缩,对于方法全限定来说,组成成分:大小写英文字母,数字,特殊字符。在开发过程中,一个标准且合格的类名,方法名需要做到见名知意,根据有效统计,方法全限定99%以上由大小写英文字母组成。

算法实现

压缩原理简述
将char字符的空闲bit位来存储有效的数据。比如通过将 a ~ z 映射成 1 ~ 26 的数字,并将Char类型以5bit为一组分为高、中、低三组,分别来存储一个数字(这一个数字代表一个字符)

建立字符串头结构: Head

在Java代码编写过程中,一个全限定字符串中的大写字母占比相对较小,因此,通过使用前补充字符的方式来记录全限定字符串中的大写字母。一个字符串如果是有限且不可变的,那么所组成他们的字符之间的相对位置是确定的。实现算法如下:

public char[] build(String s) {
            ...
    for (int i = 0; i < len; i++) {
        c = s.charAt(i);
        b = Character.isUpperCase(c);
        if (b || c == FILL) {
            if (i - lastIndex >= maxDistance) {
                maxDistance = i - lastIndex;
            }
            upCharIndex.add(i - lastIndex);
            lastIndex = i;
       }
    if (b) upCharCount++;
    }
    ...
    return handleHead(type);
} 

在压缩前的第一步:在字符串开始时,保存并记录大写字母的位置和每一个大写字母之间的距离。(小数点认为是一个大写字母)。

 private char[] handleHead(int type) {
        ...
    int k, j;
    //记录大写字母位置与char中
    for (int i = 0; i < chars.length; i++) {
        if (i == 0) {
            for (j = 0, k = 1; j < ch1; j++, k++) {
                ch = bitToLeft(ch, upCharIndex.get(j), 12 - (k * stepDistance));
            }
            chars[i] = ch;
        } else {
            char emptyCh = FILL;
            emptyCh &= 0;
            int start = (i - 1) * sizeOfChar + ch1;
            for (j = start, k = 1; j < start + sizeOfChar; j++, k++) {
                if (j == upCharIndex.size())
                    break;
                emptyCh = bitToLeft(emptyCh, upCharIndex.get(j), 16 - (k * stepDistance));
            }
            chars[i] = emptyCh;
        }
    }
    return chars;
} 

Head的最小长度为:1个Char,也就是16bit。在16bit的高2位存储步长。接下来的2位记录真正的Head长度大小。

head长度:Head最小的长度是1个Char,其中记录步长和Head长度的信息。目前,填充长度最长为 3+1,可通过步长算法完成Head长度的扩展。扩展方法:getTypeBySize、getSizeByType

存储大写字母的位置时,按照步长来填充。例如:步长为3,那么就意味着每3个bit存储一个大写字母位置。
Head的长度取决于填充了多少个步长。例如:填充10个步长为3的位置,需要16%3等于5,那么就需要两个Char.

步长: 步长是一个可变的量,在算法设计中,提供如下几种步长类型:(据统计最长英文单词:45个字符)

    STEP_0:表示没有大写字母
    STEP_3:表示大写字母距离(0,8),步长为3
    STEP_15:表示大写字母间距离[816),步长为4
    STEP_OVER_15:表示大写字母间距离[1663),步长为6

建立压缩字符串内容:Content

Content压缩是按照1个Char的高、中、低三位中分别存储一个字符的算法完成的。具体的实现FormatUtil.ContentBuilder:

填充: 由于字符串并不都是3的倍数。为了保证原字符串的完整性,在分割字符串之前先给原来字符串填充一定数量的字符,保证其在分割的时候可以每3个字符为一组。

 public String handleString(String s) {
    int f;
    if ((f = s.length() % 3) != 0) {
        StringBuilder sBuilder = new StringBuilder(s);
        for (f = 3 - f; f > 0; f--)
            sBuilder.append(FILL);
        s = sBuilder.toString();
    }
    return s.toLowerCase();
} 

分割替换: 在完成填充以后,将原来的字符串以三个为一组分割成多个组。对于字符串中的数字或者特殊字符,我们在mapping文件中并没有形成映射,因此,一旦出现,那么就通过“MASK”去代替。

public short buildShort(char high, char mid, char low) {
    short b = 0;

    b |= getShortFromMapping(high) << 10;
    b |= getShortFromMapping(mid) << 5;
    b |= getShortFromMapping(low);
    return b;
}

public short getShortFromMapping(char ch) {
    if (mapping.containsKey(ch))
        return mapping.get(ch);
    return mapping.get(MASK);
} 

建立完成压缩后字符串

Head + content = 压缩完成后的字符串。

总结

在算法构思前期,理论压缩效率可达66%:将三个Char存储在一个Char中,不过从最后包大小的总压缩率来计算,压缩率应该只有50%左右。出现这种的情况的原因如下:文章来源地址https://www.toymoban.com/news/detail-507973.html

    字符串长度不都是3的整数倍,有多余的字符填充
    压缩完以后的字符并不是一个正确的ASCII码,在Java底层对字符集的编解码过程中,将其认为是汉字,一次一个字符会被解码成两个字符大小。

到了这里,关于有限字符集的字符串压缩算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【每日挠头算法题(2)】压缩字符串|仅执行一次字符串交换能否使两个字符串相等

    点我直达~ 使用双指针法 大致过程如下: 使用双指针,分别读(read),写(write)指针,读指针不断向后走,当read指针走到最后位置处时,或read和read的下一个位置与当前位置不相等时,说明该read指针走到了某一串相同子串的最后位置处。 此时write指针开始记录具体的字符

    2024年02月08日
    浏览(53)
  • MySQL 字符集概念与原理及如何配置字符集 - 超详细图文详解

    目录 一、字符集概念 1、字符(Character) 2、字符编码 3、字符集(Character set) 二、字符集原理 1、ASCII字符集 2、GB2312 3、GBK 4、GB18030 5、BIG5 6、Unicode 编码 三、字符序 四、MySQL字符集 字符序 1、mysql 字符集 2、mysql 字符序 3、字符集与字符序的关系 五、MySQL 数据存储字符集

    2024年02月04日
    浏览(55)
  • HTML 字符集

    HTML5 中的默认字符集为 UTF-8。 数字 ASCII ANSI 8859-1 UTF-8 描述 32 space 33 ! ! ! ! exclamation mark 34 \\\" \\\" \\\" \\\" quotation mark 35 # # # # number sign 36 $ $ $ $ dollar sign 37 % % % % percent sign 38 ampersand 39 \\\' \\\' \\\' \\\' apostrophe 40 ( ( ( ( left parenthesis 41 ) ) ) ) right parenthesis

    2023年04月25日
    浏览(63)
  • Linux字符集详解

    计算机中处理和储存信息都是用二进制数表示的;而我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果。通俗的说,按照某种规则将字符存储在计算机中,如’a’用97表示,称为\\\"编码\\\";反之,将计算机中的二进制数解析显示出来,称为\\\"解码\\\"。在解码过程中,

    2024年02月06日
    浏览(54)
  • 字符集详解

    计算机底层不可以直接存储字符的。 计算机中底层只能存储二进制(0、1) 。 二进制是可以转换成十进制的。 结论:计算机底层可以表示成十进制编号。计算机可以给人类字符进行编号存储,这套编号规则就是字符集。 ASCII(American Standard Code for Information Interchange,美国信息交

    2024年02月07日
    浏览(44)
  • (三) MySQL字符集

    MySQL字符集包括 基字符集 (CHARACTER)与 校对规则 (COLLATION)这两个概念: latin1支持西欧字符、希腊字符等 gbk支持中文简体字符 big5支持中文繁体字符 utf8几乎支持世界所有国家的字符 utf8mb4是真正意义上的utf-8 查看当前数据库默认的字符集: SHOW VARIABLES like \\\'character%\\\'; MySQL在

    2024年01月24日
    浏览(60)
  • oracle 字符集

      NLS_NCHAR_CHARACTERSET  国家字符集 NLS_CHARACTERSET  字符集 -----字符集和国家字符集的区别 字符集用来存储CHAR,VARCHAR2,CLOB,LONG等类型数据。 国家字符集用以存储NCHAR,NVARCHAR2,NCLOB等类型数据。

    2024年01月24日
    浏览(48)
  • TiDB字符集和时区

    TiDB 字符集和时区 mysql select @@version; +--------------------------------------+ | @@version | +--------------------------------------+ | 5.7.10-TiDB-v2.1.0-beta-179-g5a0fd2d | +--------------------------------------+ 1 row in set (0.00 sec) mysql show variables like \\\'coll%\\\'; +----------------------+-------------------+ | Variable_name | Value | +---

    2024年02月16日
    浏览(56)
  • 【PG】PostgreSQL字符集

    目录 设置字符集 1 设置集群默认的字符集编码 2 设置数据库的字符集编码 查看字符集 1 查看数据字符集编码  2 查看服务端字符集 3 查看客户端字符集 4 查看默认的排序规则和字符分类  被支持的字符集 PostgreSQL里面的字符集支持你能够以各种字符集存储文本,包括 单字节字

    2024年02月08日
    浏览(49)
  • 常用ASCII字符集(做题用)

    以下是ASCII字符集的一部分,包括可打印字符和控制字符。ASCII(美国信息交换标准代码)是一种用于表示文本字符的字符编码标准,使用7位二进制数来表示128个不同的字符。 这是ASCII字符集的一个简短示例。其中包含了常见的可打印字符、数字和标点符号,以及控制字符。

    2024年02月08日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包