1

我得到一个可能很大的数字 (UInt.MaxValue: 18446744073709551615) 作为一个正常的 base10 数字。这个数字最终会变成一个文件名:12345678945768.txt

由于 Windows 上的文件名不仅限于数字,我想将其“压缩”为较短的字符串,但需要确保字符串可以映射回数字。

对于较小的数字:0001365555,十六进制比其他任何数字都短得多。到目前为止,我发现的所有内容都表明 Base64 最短,但事实并非如此。

到目前为止,我已经尝试过:

//18446744073709551615 - 20
UInt64 i = UInt64.MaxValue; // 0001365555

//"//////////8=" - 12
string encoded = Convert.ToBase64String(BitConverter.GetBytes(i)); 

//"FFFFFFFFFFFFFFFF" - 16
string hexed = i.ToString("X"); 

//"MTg0NDY3NDQwNzM3MDk1NTE2MTU=" - 28
string utf = Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(i.ToString())); 

有没有更好的方法来“压缩”整数以转换类似于十六进制但使用 00-zz 而不仅仅是 00-FF?

提前致谢!

4

5 回答 5

4

到目前为止,我发现的所有内容都表明 Base64 最短,但事实并非如此。

您不想使用 Base64。Base64 编码的文本可以使用该/字符,这在 Windows 上的文件名中是不允许的。你需要想出别的办法。

还有什么?

好吧,您可以编写自己的基本转换,可能是这样的:

public static string Convert(ulong number)
{
    var validCharacters = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890!@#$%^&()_-";
    char[] charArray = validCharacters.ToCharArray();
    var buffer = new StringBuilder();
    var quotient = number;
    ulong remainder;
    while (quotient != 0)
    {
        remainder = quotient % (ulong)charArray.LongLength;
        quotient = quotient / (ulong)charArray.LongLength;
        buffer.Insert(0, charArray[remainder].ToString());
    }
    return buffer.ToString();
}

这是“base-73”结果, 中的字符越多validCharacters,输出越小。随意添加更多,只要它们是您文件系统中的合法字符。

于 2011-11-17T21:13:20.983 回答
2

您允许的字符集是什么?如果您可以识别 7132 个可以安全使用的不同 Unicode 字符,则可以将 64 位数字编码为五个 Unicode 字符。另一方面,并​​非所有文件系统都支持此类字符。如果可以识别 139 个合法字符,则可以将数据压缩为 9 个字符的字符串。使用 85,您可以使用十个字符的字符串。

于 2011-11-17T21:05:54.340 回答
1

你误用了 Base64。

(System.Text.Encoding.ASCII.GetBytes(i.ToString())

这会产生一个字节序列,其中包含 base10 编码的整数并在 base64 中再次对其进行编码。这显然是低效的。

您需要获取整数的原始字节并使用 base64 对其进行编码。哪种编码最有效取决于您要允许的字符数。如果你想要笑

你应该在数组的一侧修剪 0 个字节。

var bytes=BitConverter.GetBytes(input);
int len=8;
for(int i=7;i>=0;i--)
{
  if(bytes[i]!=0)
  {
    len=i+1;
    break;
  }
}
string s=Convert.ToBase64String(bytes,0,len).ReplaceString('/','-');

请注意,这在大端系统上不会按预期工作。

但也许您应该一起避免字节编码,而只使用具有更高基数的整数编码。

一个简单的版本可能是:

string digitChars="0123..."
while(i!=0)
{
  int digit=i%digitChars.Length;
  i/=digitChars.Length;
  result=digitChars[digit]+result;
}
于 2011-11-17T21:03:59.023 回答
0

这是一个实现:非常长的正整数的基本转换

于 2011-11-17T21:09:10.410 回答
0

这是一些使用上面 vcsjones 答案的代码,但也包括反向转换。就像在他的回答中一样,如果需要减少字符串大小,请随意添加更多字符。下面的字符为 ulong.MaxValue 生成大小为 13 的字符串。

private const string _conversionCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

public static string UlongToCompressedString(ulong number)
{
    char[] charArray = _conversionCharacters.ToCharArray();
    var buffer = new System.Text.StringBuilder();
    var quotient = number;
    ulong remainder;
    do
    {
        remainder = quotient % (ulong)charArray.LongLength;
        quotient = quotient / (ulong)charArray.LongLength;
        buffer.Insert(0, charArray[remainder].ToString());
    } while (quotient != 0);
    return buffer.ToString();
}

public static ulong? CompressedStringToULong(string compressedNumber)
{
    if (compressedNumber == null)
        return null;

    if (compressedNumber.Length == 0))
        return 0;
    
    ulong result   = 0;
    int   baseNum  = _conversionCharacters.Length;
    ulong baseMult = 1;
    
    for (int i=compressedNumber.Length-1; i>=0; i--)
    {
        int cPos = _conversionCharacters.IndexOf(compressedNumber[i]);
        if (cPos < 0)
            return null;
        result += baseMult * (ulong)cPos;
        baseMult *= (ulong)baseNum;
    }

    return result;
}
于 2020-06-05T16:28:36.090 回答