目前我能找到的最接近的是yEnc(2%)和ASCII85(25%的开销)。yEnc存在一些问题,主要是因为它使用8位字符集。这也引发了另一个想法:是否有基于UTF-8字符集的二进制到文本编码?
目前我能找到的最接近的是yEnc(2%)和ASCII85(25%的开销)。yEnc存在一些问题,主要是因为它使用8位字符集。这也引发了另一个想法:是否有基于UTF-8字符集的二进制到文本编码?
这实际上取决于二进制数据的性质以及“文本”对输出的约束条件。
首先,如果您的二进制数据未经压缩,请在编码之前进行压缩。然后,我们可以假设1/0或单个字节的分布基本上是随机的。
现在:为什么需要文本?通常,这是因为通信渠道不能平等通过所有字符。例如,您可能需要纯ASCII文本,其可打印字符范围从0x20-0x7E。您有95个字符可供使用。每个字符理论上可以编码log2(95) ~= 6.57位/字符。很容易定义一个转换,效果相当不错。
但是:如果您需要分隔符呢?现在您只有94个字符等等。因此,编码选择真的取决于您的要求。
举个非常愚蠢的例子:如果您的通道可以毫无问题地传递所有256个字符,并且您不需要任何分隔符,则可以编写一个简单的转换,实现100%的效率。:-) 如何实现留给读者作为练习。
UTF-8不适合任意编码的二进制数据传输。它可以使用14%的开销传输值0x01-0x7F。我不确定0x00是否合法;可能不是。但是,UTF-8中大于0x80的任何内容都会扩展为多个字节。我将UTF-8视为传递0x01-0x7F或126个唯一字符的受限频道。如果您不需要分隔符,则可以每个字符传输6.98位。
此问题的通用解决方案:假设N个字符的字母表的二进制编码为0到N-1。(如果编码不是所假定的,则使用查找表在我们的中间表示0..N-1和实际发送和接收的内容之间进行转换。)
假设字母表中有95个字符。现在:其中一些符号将表示6位,而一些符号将表示7位。如果我们有A个6位符号和B个7位符号,则:
A+B=95(符号总数)
2A+B=128(可以制作的7位前缀总数。您可以使用6位符号启动2个前缀,或者使用7位符号启动1个前缀。) 解决这个问题,您会得到:A=33,B=62。现在建立一个符号表:原始 编码 000000 0000000 000001 0000001 ... 100000 0100000 1000010 0100001 1000011 0100010 ... 1111110 1011101 1111111 1011110编码时,首先移开输入的6位。如果这6位大于或等于100001,则再移动另外1位。然后查找对应的7位输出代码,将其转换以适合输出空间并发送。每次迭代将移动输入的6或7位。 解码时,接受一个字节并将其转换为原始输出代码。如果原始代码小于0100001,则将相应的6位移动到输出中。否则将相应的7位移动到输出中。每次迭代将生成6-7位输出。 对于均匀分布的数据,我认为这是最优的。如果您知道源中有更多的零比一个,则可能希望将7位代码映射到空间的开头,以便更有可能使用7位代码。
简短的回答是:没有,仍然没有。
我遇到了将大量信息编码为JSON字符串的问题,即UTF-8无控制字符、反斜杠和引号。
我调研了一下你可以塞入有效UTF-8字节的比特数。我不同意那些声称UTF-8带来了太多开销的答案。这不是真的。
如果你只考虑一字节序列,那么它就像标准ASCII一样强大。也就是说,每字节7位。但是如果你去掉所有的特殊字符,你会得到像Ascii85一样的东西。
但是高位平面中的控制字符要少得多。因此,如果你使用6个字节组,你将能够在每个组中编码5个字节。在输出中,你将得到任意长度(从1到6个字节)的UTF-8字符的任意组合。
这将比Ascii85给出更好的结果:5/6而不是4/5,83%的效率而不是80%。理论上,在更高的块长度下,它将变得更好:在19字节块时约为84%。
在我看来,编码过程变得太复杂了,而提供的利润非常小。因此,Ascii85或一些修改版的Ascii85(我现在正在看Z85)会更好。
basE91可为压缩的8位二进制输入生成最短的纯ASCII输出。
如果你只能使用ASCII字符并且不想使用不可打印字符的话,目前最好的编码方式是Base91。它还具有极快的编码/解码速度,因为可以使用查找表进行编码,而不像Base85需要使用缓慢的除法进行解码。
如果需要更高效率的编码,可以尝试Base122,但它不符合8位清洁规范。然而,由于它基于UTF-8编码,它对许多用途来说应该是可行的。而现在的8位清洁规范已经没有实际意义了。
需要注意的是,Base122实际上是基于Base-128的,因为6个无效值(128-122)被特别编码,以便一系列14位可以用最多2个字节来表示,就像Base-128一样,其中7位将编码为1个字节,并且实际上可以优化为比Base-128更有效率的方案。
Base-122编码
Base-122编码每次处理7位输入数据。如果该块映射到合法字符,则使用单字节UTF-8字符进行编码:
0xxxxxxx
。如果该块将映射到非法字符,则使用双字节UTF-8字符:110xxxxx 10xxxxxx
。由于只有六个非法代码点,我们只需用三位来区分它们。将这些位表示为sss
给出了格式:110sssxx 10xxxxxx
。剩余的八位似乎可以编码更多的输入数据。不幸的是,表示小于0x80的代码点的双字节UTF-8字符是无效的。浏览器将解析无效的UTF-8字符为错误字符。强制使用大于0x80的代码点的一种简单方法是使用格式110sss1x 10xxxxxx
,相当于按位或运算符与0x80(这可能可以改进,请参见§4)。图3总结了完整的Base-122编码。
除了维基百科上列出的编码方式,还有Bommanews:
B-News(或bommanews)是为了减轻UUEncode和Base64编码固有的开销而开发的:它使用一种新的编码方法将二进制数据嵌入文本消息中。这种方法消耗更多的CPU资源,但它成功地将损失从UUEncode的约40%降低到3.5%(这些数字之间的小数点不是您显示器上的污垢),同时仍避免在消息正文中使用ANSI控制代码。
它类似于yEnc:来源
yEnc比B-News的CPU占用要少,并且达到了大致相同的低开销水平,但它并没有避免使用所有控制代码,只是省略了那些在某些服务器上观察到具有不良影响的代码,这意味着它比B-News稍微不符合RFC标准。
7F
可能存在,并且在IBM OEM字符集中是一个控制码。即使在Windows代码页中,81
、8D
、8F
、90
和9D
也是控制字符。当打印这些内容时要小心,因为数据将会丢失。 - Maarten Bodewes如果您正在寻找一种适用于大型字母表的高效编码方式,您可能想尝试escapeless。无转义252和yEnc都有1.6%的开销,但是对于前者,它是固定的并且事先已知,而对于后者,它实际上取决于字节的分布,范围从0到100%。