Кратчайший способ представления UInt64 в виде строки - PullRequest
0 голосов
/ 18 ноября 2011

Я получаю возможно большое число (UInt.MaxValue: 18446744073709551615) как обычное число base10.Этот номер в конечном итоге станет именем файла: 12345678945768.txt

Поскольку имена файлов в Windows не ограничиваются только числовыми цифрами, я хотел бы «сжать» их до более короткой строки, но нужно убедиться, что строкиможет быть преобразован обратно в число.

Для меньших чисел: 0001365555, hexed намного короче, чем все остальное.Все, что я нашел до сих пор, говорит о том, что 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 ]

3 голосов
/ 18 ноября 2011

Все, что я нашел до сих пор, говорит, что 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, тем меньше будет вывод. Не стесняйтесь добавлять больше, если они являются допустимыми символами в вашей файловой системе.

3 голосов
/ 18 ноября 2011

Какой ваш набор символов разрешен?Если бы вы могли идентифицировать 7132 различных символов Юникода, которые можно было бы безопасно использовать, вы могли бы закодировать 64-разрядное число в виде пяти символов Юникода.С другой стороны, не все файловые системы будут поддерживать такие символы.Если бы вы могли идентифицировать 139 допустимых символов, вы могли бы сжать данные в строку из девяти символов.С 85 вы можете использовать десятисимвольную строку.

1 голос
/ 18 ноября 2011

Вы неправильно использовали Base64.

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

Это создает последовательность байтов, которая содержит закодированное в base10 целое число, и кодирует ее снова в base64.Это явно неэффективно.

Вам нужно получить необработанные байты целого числа и кодировать их с помощью base64.Какая кодировка является наиболее эффективной, зависит от того, сколько символов вы хотите разрешить.Если вам нужно sho

И вы должны обрезать 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;
}
0 голосов
/ 18 ноября 2011
...