【问题标题】:Compressing a Hex String in JavaScript/NodeJS在 JavaScript/NodeJS 中压缩十六进制字符串
【发布时间】:2012-07-31 05:41:57
【问题描述】:

我的应用生成链接,其中包含十六进制字符串,例如:37c1fbcabbc31f2f8d2ad31ceb91cd8d0d189ca5963dc6d353188d3d5e75b8b3e401d4e74e9b3e02efbff0792cda5c4620cb3b1f84aeb47b8d2225cd40e761a5。我真的很想让它们更短,就像 Compressing a hex string in Ruby/Rails 中提到的 Ruby 解决方案一样。

有没有办法在 JavaScript/NodeJS 中做到这一点?

【问题讨论】:

    标签: javascript node.js compression hex


    【解决方案1】:

    您可以使用toStringparseInt 方法,它们基本上与您在链接中提到的方法做同样的事情:

    var hexString = "4b3fc1400";
    var b36 = parseInt(hexString, 16).toString(36); // "9a29mgw"
    

    要转换回来,你只需要做相反的事情:

    hexString = parseInt(b36, 36).toString(16); // "4b3fc1400"
    

    您的字符串的唯一问题是,它太大了,无法像 JavaScript 中的数字那样构成威胁。你应该把它们分成大块。 JavaScript 的数字精确到 2^53(加号),因此您可以处理的最大正数是 0x20000000000000(十六进制,即 9007199254740992 十进制);您可以使用准确性来处理块:

    var hexString = "37c1fbcabbc31f2f8d2ad31ceb91cd8d0d189ca5963dc6d353188d3d5e75b8b3e401d4e74e9b3e02efbff0792cda5c4620cb3b1f84aeb47b8d2225cd40e761a5"
    
    var b36 = "", b16 = "";
    
    var chunk, intChunk;
    
    // 14 is the length of 0x20000000000000 (2^53 in base 16)
    
    for (var i = 0, max = 14; i < hexString.length; i += max) {
        chunk = hexString.substr(i, max);
        intChunk = parseInt(chunk, 16);
    
        if (intChunk.toString(16) !== chunk) {
            intChunk = parseInt(hexString.substr(i, max - 1), 16);
            i -= 1;
        }
    
        b36 += intChunk.toString(36)
    }
    
    // 11 is the length of 2gosa7pa2gv (2^53 in base 36)
    
    for (var i = 0, max = 11; i < b36.length; i += max ) {
        chunk = b36.substr(i, max);
        intChunk = parseInt(chunk, 36);
    
        if (intChunk.toString(36) !== chunk) {
            intChunk = parseInt(b36.substr(i, max - 1), 36);
            i -= 1;
        }
    
        b16 += intChunk.toString(16)
    }
    
    console.log(hexString);
    console.log(b36);
    console.log(b16);
    

    更新:您也可以使用 base 62 而不是 36 来压缩更多,但请注意 JS 最多支持 base 36,因此您需要手动实现 personal notation(我相信那里已经有一些实现了)。

    【讨论】:

    • 我如何从字符串转换为 base36,需要它来尝试学习 reddit 的 api,其中全名是 t2_36basesencodedHere reddit.com/dev/api#fullnames
    【解决方案2】:

    最简单、最快的做法是定义一组 64 个安全字符以供在 URL 中使用,例如 A-Z、a-z、0-9、_ 和 $。然后将每三个十六进制数字(每个 4 位)编码为两个安全字符(每个 6 位)。这不需要乘法和除法,它可以用于任意长的字符串。

    您需要在字符串末尾选择第 65 个字符以指示是否使用最后一个四位片段。否则,对于偶数个字符的字符串,您将产生歧义。我们称之为2n。然后有 3n-13n 十六进制数字编码在其中,但无法分辨是哪个。您可以按照顺序使用特殊字符来指示其中一种情况。例如。一种 '。' (句号)。

    注意:这里选择的最后几个字符与 Base64 编码不同,因为 URL 有自己的安全标点字符定义。见RFC 1738

    【讨论】:

      【解决方案3】:

      node int-encoder 这样做,使用已经提到的策略。

      它还支持大数

      npm install int-encoder
      
      var en = require('int-encoder');
      
      //simple integer conversion
      en.encode(12345678); // "ZXP0"
      en.decode('ZXP0'); // 12345678
      
      //convert big hex number using optional base argument
      en.encode('e6c6b53d3c8160b22dad35a0f705ec09', 16); // 'hbDcW9aE89tzLYjDgyzajJ'
      en.decode('hbDcW9aE89tzLYjDgyzajJ', 16); // 'e6c6b53d3c8160b22dad35a0f705ec09'
      

      【讨论】:

        猜你喜欢
        • 2010-12-31
        • 2020-06-01
        • 2016-11-01
        • 2014-03-07
        • 2017-03-21
        • 1970-01-01
        • 2011-11-02
        • 2012-12-06
        • 2020-11-11
        相关资源
        最近更新 更多