我可以使用哪种类型的编码来缩短字符串?


13

我对编码我拥有的字符串感兴趣,并且我很好奇是否存在可以使用的编码类型,该编码类型仅包括字母和数字字符,并且最好缩短表示该字符串所需的字符数。

到目前为止,我已经研究过使用Base64编码执行此操作,但是它似乎使我的字符串更长,有时包括==我想避免的字符串。例:

测试名称| 120101

变成

dGVzdCBuYW1lfDEyMDEwMQ ==

长度从16到24个字符,并且包含非字母数字。

有人知道我可以使用满足我要求的其他编码类型吗?奖励点在于它是内置在.NET框架中还是存在将进行编码的第三方库。


1
不能像霍夫曼编码那样使用无损压缩!它们非常适合文本...但是在接收端,您应该真正了解为获取文本所做的这种变异。

6
您是在描述压缩而不是编码
Andy Smith,

@Andrew-好的,有什么建议吗?
2011年

Answers:


30

在Base64中,最后的'='或'=='仅用于使字符数为4的倍数。您可以将其删除,因为您以后可以随时将其放回去。请注意,之所以称为Base64,是因为它使用64个不同的字符。大写字母,小写字母和数字为62。因此Base64还使用“ /”和“ +”,这可能会也可能不适合您的账单。

通常,如果您想将任意字节序列编码为字母数字字符,则某处一定会有一些长度扩展,因为一个字节有256个可能的值,而只有62个字母数字字符。有时也称为信鸽原理。编码方案的平均长度扩展必须为因数log 256 / log 62 = 1.344(所有字节序列的平均值);否则,这意味着有些鸽子在某个地方被压死了,并且您将不会受到伤害而无法将它们归还(这意味着:两个截然不同的字符串编码为相同的字符串,因此解码无法可靠地工作)。

现在,您的字符串很有可能不完全是“一致随机字节的序列”;您的字符串具有某些含义,这意味着大多数可能的字节序列都不会出现,因为它们毫无意义。在此基础上,您可能可以设计出一种编码方案,该方案的长度扩展比通用Base64(或需要严格遵守字母数字字符的Base62)少。这是无损数据压缩。它在明确定义的可能作为输入出现的概率模型上工作。

简介:一种不存在将字符串编码为字母数字序列的通用方案,这样就不会出现或几乎不出现长度扩展;这在数学上是不可能的。可能存在针对您期望的输入字符串量身定制的特定方案(但是由于您不告诉您可能遇到的字符串类型,因此没有人可以帮助您)。


1
+1,出色的解释。我不知道=/ ==与长度必须为4的倍数有关。我可能可以根据需要解决此问题
Abe Miessler 2011年

请注意,这是假设缺少信鸽。Unicode有很多字母。我们确实需要对实际问题有更好的理解。
MSalters 2011年

@Tom如何使用对数除法计算平均长度扩展因子?根据en.wikipedia.org/wiki/Base64中的图表,它完全具有直觉意义,即对于每个未编码的字符,Base64中需要使用4/3个字符来表示。只是想知道你是如何与数学同样的结论...谢谢:)
乔纳森·林

我的问题很愚蠢。log(256)= 8位,log(64)= 6位,因此Base64的比率为8/6 = 4/3 = 1.333。干杯。
林俊杰

4

通常在接收系统无法处理字符时对字符进行重新编码。例如,BASE64使用6位(2 6,因此64个)字符来表示数据,以表示更长的数据序列(末尾有时出现的“ ==”是用于对齐的填充)。这是因为您电子邮件中的图片文件中可能包含0xFE,并且您的邮件服务器将不满意发送该图片文件(或其他任何传统的非打印字符)。

没有“减小大小”的编码。编码只是位到它们表示的字符的映射。也就是说,ASCII是7位字符集(编码),通常存储在8位空间中。如果您限制可接受的范围,则还可以清除控制字符。

使用此方法意味着您必须在位级别上写东西,并且它还会影响机器速度和指令,因为所有现代机器的对齐方式都是8位的倍数。例如,这就是为什么Unicode是UTF-8,UTF-16和UTF-32的原因。

如果您这样做是出于安全考虑(这就是为什么将其发布到Security.SE上,对吗?),只需过滤掉内容并正常存储它们即可。如果这样做是为了节省空间,请考虑是否值得所有额外的代码和较慢的访问时间(因为大多数条目将跨越地址边界)值得节省空间。

顺便说一句,以下是CS课程的摘录,我们必须将ASCII从8位存储转换为7位:

    memset(dest,0x00,8);
    memcpy(dest, source, length);

    for (int i = 0; i < 8; i++) {
            if (dest[i] & 0x80) {
                    fprintf(stderr, "%s: %s\n", dest, "Illegal byte sequence");
                    exit(EILSEQ);
            }
    }

    dest[0] = 0x7F & dest[0] | 0x80 & dest[1] << 7;
    dest[1] = 0x3F & dest[1] >> 1 | 0xC0 & dest[2] << 6;
    dest[2] = 0x1F & dest[2] >> 2 | 0xE0 & dest[3] << 5;
    dest[3] = 0x0F & dest[3] >> 3 | 0xF0 & dest[4] << 4;
    dest[4] = 0x07 & dest[4] >> 4 | 0xF8 & dest[5] << 3;
    dest[5] = 0x03 & dest[5] >> 5 | 0xFC & dest[6] << 2;
    dest[6] = 0x01 & dest[6] >> 6 | 0xFE & dest[7] << 1;
    dest[7] = 0x00; //Clearing out

2

您可以使用例如gzip,bzip2或lzma压缩数据,然后通过base64运行以限制使用的字符集。这仅对大于或等于数百个字节的较大字符串有用。


1

为什么不使用LZ压缩?这可能是压缩字符串的一种不错的方法,但是在长字符串的情况下会更有效。您要编码的目标字符串多长时间?


LZ压缩与attir建议中提到的gzip或bzip2相比如何?
NoChance 2011年

gzip基于LZ和Huffman编码。有关LZ的更多信息,请访问en.wikipedia.org/wiki/LZ77
A.Rashad 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.