Как я могу быстро кодировать, а затем сжать короткую строку, содержащую числа в C # - PullRequest
6 голосов
/ 15 июня 2011

У меня есть строки, которые выглядят следующим образом:

000101456890
348324000433
888000033380

Это строки одинаковой длины, и они содержат только цифры.

Я хотел бы найти способ кодирования и затем сжатия (уменьшения длины) строк.Алгоритм сжатия нужно будет просто сжать до символов ASCII, поскольку они будут использоваться в качестве ссылок на веб-страницы.

Так, например:

www.stackoverflow.com/000101456890  goes to www.stackoverflow.com/aJks

Есть ли какой-нибудь способ, которым я мог бы сделать это, какой-то метод, который бы выполнял работу по сжатию быстро.

Спасибо,

Ответы [ 2 ]

8 голосов
/ 15 июня 2011

Чтобы сделать это просто , вы можете рассматривать каждого как long (много места там) и закодировать в шестнадцатеричном формате; что дает вам:

60c1bfa
5119ba72b1
cec0ed3264

base-64 будет короче, но вам нужно рассматривать его как big-endian (обратите внимание, что в большинстве .NET используется метод little-endian) и игнорировать начальные 0 байтов. Это дает вам:

Bgwb+g==
URm6crE=
zsDtMmQ=

Например:

    static void Main()
    {
        long x = 000101456890L, y = 348324000433L, z = 888000033380L;

        Console.WriteLine(Convert.ToString(x, 16));
        Console.WriteLine(Convert.ToString(y, 16));
        Console.WriteLine(Convert.ToString(y, 16));

        Console.WriteLine(Pack(x));
        Console.WriteLine(Pack(y));
        Console.WriteLine(Pack(z));

        Console.WriteLine(Convert.ToInt64("60c1bfa", 16).ToString().PadLeft(12, '0'));
        Console.WriteLine(Convert.ToInt64("5119ba72b1", 16).ToString().PadLeft(12, '0'));
        Console.WriteLine(Convert.ToInt64("cec0ed3264", 16).ToString().PadLeft(12, '0'));

        Console.WriteLine(Unpack("Bgwb+g==").ToString().PadLeft(12, '0'));
        Console.WriteLine(Unpack("URm6crE=").ToString().PadLeft(12, '0'));
        Console.WriteLine(Unpack("zsDtMmQ=").ToString().PadLeft(12, '0'));

    }
    static string Pack(long value)
    {
        ulong a = (ulong)value; // make shift easy
        List<byte> bytes = new List<byte>(8);
        while (a != 0)
        {
            bytes.Add((byte)a);
            a >>= 8;
        }
        bytes.Reverse();
        var chunk = bytes.ToArray();
        return Convert.ToBase64String(chunk);
    }
    static long Unpack(string value)
    {
        var chunk = Convert.FromBase64String(value);
        ulong a = 0;
        for (int i = 0; i < chunk.Length; i++)
        {
            a <<= 8;
            a |= chunk[i];
        }
        return (long)a;
    }
2 голосов
/ 15 июня 2011

Я не уверен, что Base 64 безопасна для URL, поскольку в индексной таблице есть символ '/' (функция пакета, предоставленная в выбранном ответе, приведет к появлению строк, не безопасных для URL).

Вы можете рассмотреть возможность замены символа '/' на что-то более удобное для URL или использовать другую базу. База 62 сделает это здесь, например.

Вот общий код, который переводит взад и вперед из десятичной в любую числовую базу <= 64 (вероятно, быстрее, чем преобразование в байты и затем использование Convert.ToBase64String ()): </p>

static void Main()
{
    Console.WriteLine(Decode("101456890", 10));
    Console.WriteLine(Encode(101456890, 62));
    Console.WriteLine(Decode("6rhZS", 62));
    //Result:
    //101456890
    //6rhZS
    //101456890
}

public static long Decode(string str, int baze)
{
    long result = 0;
    int place = 1;
    for (int i = 0; i < str.Length; ++i)
    {
        result += Value(str[str.Length - 1 - i]) * place;
        place *= baze;
    }

    return result;
}

public static string Encode(long val, int baze)
{
    var buffer = new char[64];
    int place = 0;
    long q = val;
    do
    {
        buffer[place++] = Symbol(q % baze);
        q = q / baze;
    }
    while (q > 0);

    Array.Reverse(buffer, 0, place);
    return new string(buffer, 0, place);
}

public static long Value(char c)
{
    if (c == '+') return 62;
    if (c == '/') return 63;
    if (c < '0') throw new ArgumentOutOfRangeException("c");
    if (c < ':') return c - '0';
    if (c < 'A') throw new ArgumentOutOfRangeException("c");
    if (c < '[') return c - 'A' + 10;
    if (c < 'a') throw new ArgumentOutOfRangeException("c");
    if (c < '{') return c - 'a' + 36;
    throw new ArgumentOutOfRangeException("c");
}

public static char Symbol(long i)
{
    if (i < 0) throw new ArgumentOutOfRangeException("i");
    if (i < 10) return (char)('0' + i);
    if (i < 36) return (char)('A' + i - 10);
    if (i < 62) return (char)('a' + i - 36);
    if (i == 62) return '+';
    if (i == 63) return '/';
    throw new ArgumentOutOfRangeException("i");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...