【问题标题】:Java: Universal BaseN encoder/decoder working with large data sizesJava:处理大数据的通用 BaseN 编码器/解码器
【发布时间】:2017-03-23 06:49:51
【问题描述】:

我正在寻找一个不错的 Java BaseN 编码器(带有自定义字符集),它不受输入数据大小(字节数组)的限制。

类似这样的:

https://github.com/mklemm/base-n-codec-java

但是对于“无限”数据长度,没有任何不必要的内存/性能损失和“BigInteger 滥用魔法”。只是作为标准 BASE64 编码器工作的东西,但普遍适用于任何基本/字符集。欢迎任何解决方案或想法如何实现。

也许,如果有人有使用 apache BaseNCodec 的经验:

https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/BaseNCodec.html

它看起来很有希望,但是它是一个抽象类,并且可用的实现看起来比从头开始更难。


我需要将二进制数据用于自定义字符集编码器(其中字符集中的字符数是可变的,"ABCDE" = Base5"ABCDE-+*/." = Base10,...)。
更新: 来自 GitHub(上图)的“Base N Codec”似乎有问题,所以我最后使用了以下代码:

https://dzone.com/articles/base-x-encoding

【问题讨论】:

  • 如果您的基数不是 2 的幂,您如何定义一个不将数据视为潜在(非常)大整数并因此需要 BigInteger 或等价物的编码?
  • @dave_thompson_085 是的,但应该“虚拟地”逐个序列地完成,如有必要(不直接使用 BigInteger),会溢出到另一个序列。否则,它将“针对相对较短的字节序列(最多约 1000 个字节)”(如github.com/mklemm/base-n-codec-java 中的状态)。
  • 几乎不可能,如果“通用”是指解码/编码现有标准,如 Base85、Base64 等(不同的填充策略和分组方法)。如果你的意思是像 Integer.toString(i, radix) 那么这个用例是什么?
  • @Durandal 用例:我需要将它用于自定义字符集编码器的二进制数据(其中字符集中的字符数是可变的,"ABCDE" = Base5"ABCDE-+*/." = Base10,...)。
  • 也许我的问题不够精确。决定性的一点是,您是否绝对需要以尽可能少的浪费位对二进制数据进行编码(将整个流视为一个数字),或者一些浪费不是问题(例如 Base85 编码在 5 个符号中编码 4 个字节,仅产生 85^5 种可能性中的 2^32 个)。如果您只是寻求使用有限的符号集对传输进行编码,接受一些浪费的位,它会将问题简化为只需选择大量符号来编码相当少的字节数。

标签: java string converter encoder base-n


【解决方案1】:

一般答案:否。特殊情况:是,对于底数是 2 的幂。

为什么?因为 Q 中的思想处于“激烈竞争”中(实际上可能是“矛盾”)。

  1. 作为输入,您希望在某个基数 N 中支持无限整数(将其视为 BigIntegerBaseN)。作为输出,您需要支持某个基数 M 中的无限整数(将其视为 BigIntegerBaseM)。
  2. 您想要执行基本转换 - 在数学上定义为一系列(乘法和加法)和除法。见http://www.cut-the-knot.org/recurrence/conversion.shtmlhttps://math.stackexchange.com/questions/48968/how-to-change-from-base-n-to-m
  3. 您希望找到一种无需在 BigIntegers 上(在任何实现基础中)进行乘法和除法即可计算此类结果的方法。

你能不进行乘除运算就确定乘除运算的结果吗?不。这是一个矛盾。当你得到结果时,根据定义,你已经进行了计算。

因此,这不是您能否避免计算的问题,而是如何简化计算的问题。

  • 如果 N 和/或 M 的底数是 2 的幂,则乘法/除法可以通过简单的位移计算 = 与主要流线型相同的计算。这可以通过避免 BigInteger 计算来完成。
  • 否则,您可以缓存某些重复计算,将中间结果存储在数组或 HashMap 中,然后通过流线型获得相同的计算。但是仍然需要 BigInteger 计算(但要避免冗余重复)。

希望对您的方法有所帮助。 :)

【讨论】:

    【解决方案2】:

    如果 N 是 2 的幂,则基数 N 编码非常有效,因为这样可以在固定大小的数字组和固定大小的字节之间进行转换。

    Base64:26 - 每位 6 位,因此 4 位 = 24 位 = 3 个字节。

    否则学校乘法必须在整个长度上发生,导致大量“BigInteger”计算。

    比重复地乘以/除以基数 N 更快一点,是拥有一个 N 的幂数组。

    对于将字节数组编码为数字,您可以使用 N0、N1、N2 , N3, ... 作为长度更小或相等的字节数组,并进行重复减法。

    byte 已签名,short 可能更适合。假设数字的最高字节是 98,较小的 N 次方是 12,那么大约 7 就是那个数字。

    对于将数字解码为字节数组,可能会使用相同的幂。

    玩得开心。

    【讨论】:

    • 如果我能很好地理解第二个选项,那么对于大数据量来说,它不会对资源非常友好。
    • 是的:N 的所有幂直到数字。可以懒惰和静态地完成。对于编码/解码一次相当开销。另一方面,空间需求小于 N-log(n).(n/256) 字节(n 是数字),并且您已经需要 (n/256) 字节作为数字.适合大 N。
    【解决方案3】:

    您提到了两种截然不同的方法。 Github implementation 中使用的 BaseN 算法使用在基数之间转换整数的数学符号。这相当于说 10 与 base-8 算术中的 12 或 base-2 算术中的 1010 相同。该算法将字节流解释为一个大数并转换为分配的基数。

    Base64 是一种非常不同的方法,您可以在Wikipedia Base64 page 中看到一个示例。该算法基本上将输入流拆分为每个元素的 6 位数组。 2^6 = 64,因此命名为 Base64。它有一个包含 64 个不同字符的表,并将数组(6 位)中的每个元素显示到相应的转换表中。

    我认为您需要选择两种方法之一,因为它们非常不同并且彼此不兼容。至于实现细节,如果选择第二种方法,我认为这更容易实现,因为您基本上将流分成固定大小的部分并根据您自己的表格对其进行编码。

    第一种方法可能会变得相当复杂,因为任意算术运算都依赖于相当复杂的结构。你可以看看现有的软件,再次@Wikipedia' s list of arbitrary-precision arithmetic software

    实际上,我认为在某些时候您会发现很难为您的转换获取字符(随着基数增加或位数增加),除非您将使用整个 Unicode 字母表:)。

    希望对我有所帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多