Как мне создать сокращатель URL?

Вместо этого используйте const_iterator. iterator допускает модификацию vector, поэтому вы не можете получить его из контейнера const.

Кроме того, идиоматический способ записи этого цикла использует it != students.end() вместо < ] (хотя это должно работать на vector).

630
задан Peter Mortensen 17 October 2018 в 14:20
поделиться

10 ответов

I would continue your "convert number to string" approach. However, you will realize that your proposed algorithm fails if your ID is a prime and greater than 52.

Theoretical background

You need a Bijective Function f. This is necessary so that you can find a inverse function g('abc') = 123 for your f(123) = 'abc' function. This means:

  • There must be no x1, x2 (with x1 ≠ x2) that will make f(x1) = f(x2),
  • and for every y you must be able to find an x so that f(x) = y.

How to convert the ID to a shortened URL

  1. Think of an alphabet we want to use. In your case, that's [a-zA-Z0-9]. It contains 62 letters.
  2. Take an auto-generated, unique numerical key (the auto-incremented id of a MySQL table for example).

    For this example, I will use 12510 (125 with a base of 10).

  3. Now you have to convert 12510 to X62 (base 62).

    12510 = 2×621 + 1×620 = [2,1]

    This requires the use of integer division and modulo. A pseudo-code example:

    digits = []
    
    while num > 0
     remainder = modulo(num, 62)
     digits.push(remainder)
     num = divide(num, 62)
    
    digits = digits.reverse
    

    Now map the indices 2 and 1 to your alphabet. This is how your mapping (with an array for example) could look like:

    0 → a
    1 → b
    ...
    25 → z
    ...
    52 → 0
    61 → 9
    

    With 2 → c and 1 → b, you will receive cb62 as the shortened URL.

    http://shor.ty/cb
    

Как преобразовать сокращенный URL в начальный идентификатор

Обратное еще проще. Вы просто делаете обратный поиск в вашем алфавите.

  1. e9a 62 будут преобразованы в «4-ю, 61-ю и 0-ю букву в алфавите».

    e9a 62 = [4,61,0] = 4 × 62 2 + 61 × 62 1 + 0 × 62 0 = 19158 10

  2. Теперь найдите вашу запись базы данных с WHERE id = 19158 и выполните перенаправление.

Пример реализации (предоставлен комментаторами)

792
ответ дан 22 November 2019 в 21:49
поделиться

Качественное решение Node.js / JavaScript см. В модуле id-shorttener , который тщательно протестирован и уже несколько месяцев используется в производстве.

Он обеспечивает эффективное сокращение идентификатора / URL-адреса при поддержке сменного хранилища по умолчанию Redis , и вы даже можете настроить свой короткий набор символов идентификатора и определить, является ли сокращение идемпотентным . Это важное различие, которое учитывают не все сокращатели URL-адресов.

В отношении других ответов здесь, этот модуль реализует превосходный принятый ответ Марселя Джекверта выше.

В основе решения лежит следующий фрагмент Redis Lua :

local sequence = redis.call('incr', KEYS[1])

local chars = '0123456789ABCDEFGHJKLMNPQRSTUVWXYZ_abcdefghijkmnopqrstuvwxyz'
local remaining = sequence
local slug = ''

while (remaining > 0) do
  local d = (remaining % 60)
  local character = string.sub(chars, d + 1, d + 1)

  slug = character .. slug
  remaining = (remaining - d) / 60
end

redis.call('hset', KEYS[2], slug, ARGV[1])

return slug
0
ответ дан Peter Mortensen 17 October 2018 в 14:20
поделиться

Для аналогичного проекта, чтобы получить новый ключ, я создаю функцию-обертку вокруг генератора случайных строк , который вызывает генератор, пока не получу строку, которая еще не использовалась в моей хеш-таблице. Этот метод замедляется, как только ваше пространство имен начинает заполняться, но, как вы сказали, даже с 6 символами у вас есть достаточно пространства имен для работы.

0
ответ дан Joel Berger 17 October 2018 в 14:20
поделиться

Почему бы просто не перевести свой идентификатор в строку? Вам просто нужна функция, которая отображает цифру, скажем, от 0 до 61, в одну букву (верхний / нижний регистр) или цифру. Затем примените это для создания, скажем, четырехбуквенных кодов, и вы получите 14,7 миллионов URL-адресов.

1
ответ дан 22 November 2019 в 21:49
поделиться

Если вы не хотите повторно -изобрести колесо ... http://lilurl.sourceforge.net/

3
ответ дан 22 November 2019 в 21:49
поделиться

Мой подход: взять идентификатор базы данных, затем Base36 кодировать его . Я бы НЕ использовал как заглавные, так и строчные буквы, потому что это делает передачу этих URL-адресов по телефону кошмаром, но вы, конечно, легко могли бы расширить эту функцию до базового 62 en / decoder.

29
ответ дан 22 November 2019 в 21:49
поделиться

Не ответ на ваш вопрос, но я бы не стал использовать сокращенные URL-адреса с учетом регистра. Их трудно запомнить, как правило, нечитаемые (многие шрифты отображают 1 и l, 0 и O и другие символы очень похожи, так что почти невозможно различить их) и подвержены прямым ошибкам. Попробуйте использовать только нижний или верхний регистр.

Кроме того, попробуйте использовать формат, в котором вы смешиваете цифры и символы в предварительно определенной форме. Существуют исследования, которые показывают, что люди, как правило, запоминают одну форму лучше, чем другие (например, номера телефонов, где номера сгруппированы в определенной форме). Попробуйте что-то вроде num-char-char-num-char-char. Я знаю, что это уменьшит комбинации, особенно если у вас нет прописных и строчных букв, но это было бы более удобно и поэтому полезно.

32
ответ дан 22 November 2019 в 21:49
поделиться

Зачем вам использовать хеш?

Вы можете просто использовать простой перевод значения автоинкремента в буквенно-цифровое значение. Вы можете сделать это легко с помощью некоторого базового преобразования. Допустим, у вас есть место для символов (AZ, az, 0-9 и т. Д.), Состоящее из 40 символов, преобразуйте идентификатор в число с основанием 40 и используйте символы в качестве цифр.

54
ответ дан 22 November 2019 в 21:49
поделиться

Почему не только генерируют случайную строку и добавляют его к базовому URL? Это - очень упрощенная версия выполнения этого в C#.

static string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
static string baseUrl = "https://google.com/";

private static string RandomString(int length)
{
    char[] s = new char[length];
    Random rnd = new Random();
    for (int x = 0; x < length; x++)
    {
        s[x] = chars[rnd.Next(chars.Length)];
    }
    Thread.Sleep(10);

    return new String(s);
}

Затем просто добавляют добавление случайной строки к baseURL:

string tinyURL = baseUrl + RandomString(5);

Помнят, что это - очень упрощенная версия выполнения этого, и возможно, что метод RandomString мог создать дублирующиеся строки. В производстве Вы хотели бы взять в счете на дублирующиеся строки, чтобы гарантировать, что у Вас всегда будет уникальный URL. у меня есть некоторый код, который принимает во внимание для дублирующихся строк путем запросов таблицы базы данных, которую я мог совместно использовать, если кому-либо интересно.

0
ответ дан 22 November 2019 в 21:49
поделиться
alphabet = map(chr, range(97,123)+range(65,91)) + map(str,range(0,10))

def lookup(k, a=alphabet):
    if type(k) == int:
        return a[k]
    elif type(k) == str:
        return a.index(k)


def encode(i, a=alphabet):
    '''Takes an integer and returns it in the given base with mappings for upper/lower case letters and numbers 0-9.'''
    try:
        i = int(i)
    except Exception:
        raise TypeError("Input must be an integer.")

    def incode(i=i, p=1, a=a):
        # Here to protect p.                                                                                                                                                                                                                
        if i <= 61:
            return lookup(i)

        else:
            pval = pow(62,p)
            nval = i/pval
            remainder = i % pval
            if nval <= 61:
                return lookup(nval) + incode(i % pval)
            else:
                return incode(i, p+1)

    return incode()



def decode(s, a=alphabet):
    '''Takes a base 62 string in our alphabet and returns it in base10.'''
    try:
        s = str(s)
    except Exception:
        raise TypeError("Input must be a string.")

    return sum([lookup(i) * pow(62,p) for p,i in enumerate(list(reversed(s)))])a

Here's my version for whomever needs it.

2
ответ дан 22 November 2019 в 21:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: