Compress large Integers into smallest possible string

后端 未结 6 1603
夕颜
夕颜 2020-12-08 21:04

I have a bunch of 10 digit integers that I\'m passing in a URL. Something like: \"4294965286\", \"2292964213\". They will always be positive and always be 10 digits.

6条回答
  •  萌比男神i
    2020-12-08 21:28

    I liked @user166390 answer but I preferred a most-to-least format and thought the code could be improved since the use of dictionary is unnecessary in encode and don't need to be generated on every decode. Also I added an exception and changed to ulong since negative values are not supported.

    If somebody has further performance improvements feel free to write. Maybe if there is a better alternative to StringBuilder

    Here is the code modified by me.

            public static string EncodeNumber(ulong input)
            {
                return EncodeNumber(input, Mapping85Bit);
            }
    
            // This does not "pad" values
            private static string EncodeNumber(ulong inp, char[] map)
            {
                // use ulong count instead of int since does not matter on x64 operating system.
                ulong cnt = (ulong)map.Length;
                // value -> character
                if (inp == 0)
                {
                    return map[0].ToString();
                }
                var sb = new StringBuilder();
                while (inp > 0)
                {
                    // encoded most-to-least significant
                    ulong val = inp % cnt;
                    inp = inp / cnt;
                    sb.Insert(0, map[(int)val]);
                }
                return sb.ToString();
            }
    
            public static ulong DecodeNumber(string encoded)
            {
                return DecodeNumber(encoded, Mapping85Bit, Mapping85BitDict);
            }
    
            private static ulong DecodeNumber(string encoded, char[] map, Dictionary charMapDict)
            {
                // use ulong count instead of int since does not matter on x64 operating system.
                ulong b = (ulong)map.Length;
                ulong res = 0;
                for (var i = 0; i < encoded.Length; i++)
                {
                    char ch = encoded[i];
                    if(!charMapDict.TryGetValue(ch, out ulong val))
                    {
                        throw new ArgumentException($"Invalid encoded number: '{encoded}'. '{ch}' is not a valid character for this encoding.");
                    }
                    res = (res * b) + val;
                }
                return res;
            }
    
    
    
            // Windows file system reserved characters:     < > : " / \ | = * 
    
            /// 
            /// Compatible with file system. Originates from ASCII table except starting like Base64Url and except windows path reserved chars. Skipped '/' and '\' to prevent path problems. Skipped ' for sql problems.
            /// https://www.ascii-code.com/
            /// Does not need to be encoded for json since it doesn't use \ and ". No encoding also needed for xml since < > are also not used. That is why it is also different to https://en.wikipedia.org/wiki/Ascii85
            /// 
            public static readonly char[] Mapping85Bit = new char[] {
                'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
                'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
                'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
                'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
                'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
                'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
                '8', '9', '-', '_', ' ', '!', '#', '$', '%', '&',
                '(', ')', '+', ',', '.', ';', '?', '@', '[', ']',
                '^', '`', '{', '}', '~'
            };
            private static readonly Dictionary Mapping85BitDict = Mapping85Bit.Select((v, i) => new { Value = v, Index = (ulong)i }).ToDictionary(i => i.Value, i => i.Index);
    
        [Test]
        public void EncodeTest()
        {
            // 85Bit Encoding:
            Assert.AreEqual(EncodeNumber(85), "BA");
            Assert.AreEqual(EncodeNumber(86), "BB");
            Assert.AreEqual(EncodeNumber(3), "D");
            Assert.AreEqual(EncodeNumber(84), "~");
    
            Assert.AreEqual(EncodeNumber(0), "A");
    
            Assert.AreEqual(DecodeNumber("BA"), 85);
    
            Assert.AreEqual(DecodeNumber("BA"), 85);
            Assert.AreEqual(DecodeNumber("`"), 81);
        }
    

提交回复
热议问题