Одним из вариантов является замена идентификатора последовательностью . Вам все еще нужно будет исправить неверные данные, но это позволяет отделить URL-адрес от ключа.
Но из того, что я вижу, существующий укорочитель нуждается в некоторой работе.
При хорошем алгоритме для значения 20001
нет причин требовать более 3 символов.
Если вы используете два дополнительных «специальных» символа, вы можете получить до 64 возможных значений для каждого символа в сокращенном URL-адресе (AZ, az, 0-9 и наши специальные значения. И _), что достаточно для хранения шести битов данных. , У нас уже есть кодировка base-64 таким образом, но поскольку у вас есть только цифры, вы можете получить еще более эффективную.
Возьмите число типа 20001
, преобразуйте его в двоичный код:
100111000100001
Заполните нули слева, чтобы число двоичных цифр было кратно шести:
000100111000100001
Разбейте его на группы по шесть:
000100 111000 100001
Каждая из этих групп должна соответствовать одному возможному символу. Чтобы получить исходный номер ID, сделайте то же самое в обратном порядке.
С этой схемой вы получите 262143
, прежде чем вам нужно будет добавить 4-й символ в ваши URL, 16777215
, прежде чем добавить 5-й символ, и 1073741823
, прежде чем вы добавите 6-й.
Для забавы вот код C # для преобразования:
private static char[] charMap = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'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', '.', '_'};
public static string GetURLKey(int id)
{
if (id <= 0) return "0";
var bt = new byte[32];
int pos = 32;
while (id > 0)
{
pos--;
bt[pos] = (byte)(id % 2);
id >>= 1;
}
var bts = new Span<byte>(bt, pos, 32-pos);
var r = 6 - (bts.Length % 6);
if (r == 6) r = 0;
return string.Create((bts.Length + r) / 6, bts.ToArray(), (span, arr) =>
{
int curChar = 0, charPos = r, bitArrPos = 0, curVal = 0;
while (bitArrPos < arr.Length)
{
while (bitArrPos < arr.Length && charPos < 6)
{
curVal *= 2;
curVal += (int)arr[bitArrPos];
bitArrPos++;
charPos++;
}
span[curChar] = charMap[curVal];
curVal = 0;
charPos = 0;
curChar++;
}
});
}