Chcę utworzyć usługę skracania adresów URL, w której możesz wpisać długi adres URL w polu wejściowym, a usługa skróci adres URL do „ http://www.example.org/abcdef
”.
Zamiast „ abcdef
” może znajdować się dowolny ciąg zawierający sześć znaków a-z, A-Z and 0-9
. To daje 56 ~ 57 miliardów możliwych ciągów.
Moje podejście:
Mam tabelę bazy danych z trzema kolumnami:
- id, liczba całkowita, auto-inkrement
- długi, ciąg, długi URL podany przez użytkownika
- krótki, ciąg znaków, skrócony adres URL (lub tylko sześć znaków)
Następnie wstawiłbym długi adres URL do tabeli. Następnie wybrałbym wartość automatycznego przyrostu dla „ id
” i zbudowałem jej skrót. Ten skrót należy następnie wstawić jako „ short
”. Ale jaki hash powinienem zbudować? Algorytmy skrótu, takie jak MD5, tworzą zbyt długie ciągi znaków. Myślę, że nie używam tych algorytmów. Algorytm samokonstruujący również będzie działał.
Mój pomysł:
Dla „ http://www.google.de/
” otrzymuję identyfikator automatycznego przyrostu 239472
. Następnie wykonuję następujące kroki:
short = '';
if divisible by 2, add "a"+the result to short
if divisible by 3, add "b"+the result to short
... until I have divisors for a-z and A-Z.
Można to powtarzać, dopóki liczba nie będzie już podzielna. Czy uważasz, że to dobre podejście? Czy masz lepszy pomysł?
Ze względu na ciągłe zainteresowanie tym tematem opublikowałem wydajne rozwiązanie dla GitHub , z implementacjami dla JavaScript , PHP , Python i Java . Dodaj swoje rozwiązania, jeśli chcesz :)
encode()
idecode()
funkcje. Kroki są zatem następujące: (1) Zapisz adres URL w bazie danych (2) Uzyskaj unikalny identyfikator wiersza dla tego adresu URL z bazy danych (3) Konwertuj liczbę całkowitą na krótki ciągencode()
, np.273984
Naf5a4
(4) Użyj krótkiego ciągu (np.f4a4
) W swoim współdzielone adresy URL (5) Po otrzymaniu żądania krótkiego ciągu (np.20a8
) dekoduj ciąg do identyfikatora liczb całkowitych za pomocądecode()
(6) Wyszukaj adres URL w bazie danych dla danego identyfikatora. Do konwersji użyj: github.com/delight-im/ShortURLOdpowiedzi:
Chciałbym kontynuować twoje podejście do konwersji liczby na ciąg znaków. Jednak zdasz sobie sprawę, że zaproponowany algorytm zawiedzie, jeśli Twój identyfikator jest liczbą pierwszą i większą niż 52 .
Podłoże teoretyczne
Potrzebujesz funkcji Bijective f . Jest to konieczne, aby znaleźć funkcję odwrotną g („abc”) = 123 dla funkcji f (123) = „abc” . To znaczy:
Jak przekonwertować identyfikator na skrócony adres URL
[a-zA-Z0-9]
. Zawiera 62 litery .Weź automatycznie wygenerowany, unikalny klucz numeryczny (na przykład automatyczne zwiększenie
id
tabeli MySQL).W tym przykładzie użyję 125 10 (125 z podstawą 10).
Teraz musisz przekonwertować 125 10 na X 62 (baza 62).
125 10 = 2 × 62 1 + 1 × 62 0 =
[2,1]
Wymaga to użycia podziału na liczby całkowite i modulo. Przykład pseudokodu:
Teraz zmapuj indeksy 2 i 1 do swojego alfabetu. Tak mogłoby wyglądać twoje mapowanie (na przykład z tablicą):
Przy 2 → ci 1 → b otrzymasz cb 62 jako skrócony adres URL.
Jak rozwiązać skrócenie adresu URL do początkowego identyfikatora
Odwrotna sytuacja jest jeszcze łatwiejsza. Po prostu odwróć alfabet.
e9a 62 zostanie przetłumaczona na „4, 61 i 0 litera alfabetu”.
e9a 62 =
[4,61,0]
= 4 × 62 2 + 61 × 62 1 + 0 × 62 0 = 19158 10Teraz znajdź swój rekord bazy danych
WHERE id = 19158
i przekieruj.Przykładowe implementacje (dostarczone przez komentujących)
źródło
3792586=='F_ck'
z u zamiast _). Wykluczę niektóre znaki, takie jak u / U, aby to zminimalizować.Dlaczego miałbyś chcieć użyć skrótu?
Możesz po prostu użyć prostego tłumaczenia wartości auto-przyrostu na wartość alfanumeryczną. Możesz to łatwo zrobić za pomocą konwersji bazowej. Powiedzmy, że przestrzeń znaków (AZ, az, 0-9 itd.) Ma 40 znaków, przekonwertuj identyfikator na liczbę podstawową 40 i użyj znaków jako cyfr.
źródło
źródło
Nie jest to odpowiedź na twoje pytanie, ale nie używałbym skróconych adresów URL z rozróżnianiem wielkości liter. Są trudne do zapamiętania, zwykle nieczytelne (wiele czcionek renderuje 1 i 1, 0 i O oraz inne znaki bardzo bardzo podobne, że prawie niemożliwe jest ich odróżnienie) i wręcz podatne na błędy. Staraj się używać tylko małych lub wielkich liter.
Spróbuj także mieć format, w którym zmieszane są liczby i znaki we wstępnie zdefiniowanej formie. Istnieją badania, które pokazują, że ludzie zapamiętują jedną formę lepiej niż inne (pomyśl numery telefonów, gdzie numery są pogrupowane w określonej formie). Spróbuj czegoś takiego jak num-char-char-num-char-char. Wiem, że to obniży kombinacje, szczególnie jeśli nie masz wielkich i małych liter, ale byłoby bardziej użyteczne i dlatego przydatne.
źródło
Moje podejście: weź identyfikator bazy danych, a następnie zakoduj go w Base36 . NIE użyłbym zarówno wielkich, jak i małych liter, ponieważ to sprawia, że przesyłanie tych adresów URL przez telefon jest koszmarem, ale oczywiście można łatwo rozszerzyć tę funkcję na podstawową en / dekoder.
źródło
Oto moja klasa PHP 5.
źródło
Rozwiązanie Node.js i MongoDB
Ponieważ wiemy, jakiego formatu używa MongoDB do utworzenia nowego obiektu ObjectId z 12 bajtami.
Przykład (wybieram losową sekwencję) a1b2c3d4e5f6g7h8i9j1k2l3
Ponieważ licznik będzie unikalny, jeśli przechowujemy dane na tej samej maszynie, możemy je uzyskać bez wątpienia, że zostaną zduplikowane.
Tak więc krótki adres URL będzie licznikiem, a oto fragment kodu przy założeniu, że serwer działa poprawnie.
źródło
Wersja C #:
źródło
Możesz haszować cały adres URL, ale jeśli chcesz tylko skrócić identyfikator, postępuj zgodnie z sugestią Marcel. Napisałem tę implementację Pythona:
https://gist.github.com/778542
źródło
Wciąż zwiększam sekwencję liczb całkowitych dla domeny w bazie danych i używam Hashids do kodowania liczb całkowitych w ścieżce URL.
Uruchomiłem skrypt, aby zobaczyć, ile czasu zajmuje mu wyczerpanie długości znaku. W przypadku sześciu znaków może tworzyć
164,916,224
linki, a następnie dochodzi do siedmiu znaków. Bitly używa siedmiu znaków. Poniżej pięciu znaków wygląda dla mnie dziwnie.Hashids mogą dekodować ścieżkę URL z powrotem do liczby całkowitej, ale prostszym rozwiązaniem jest użycie całego krótkiego linku
sho.rt/ka8ds3
jako klucza podstawowego.Oto pełna koncepcja:
źródło
Jeśli nie chcesz na nowo wynajdować koła ... http://lilurl.sourceforge.net/
źródło
źródło
Oto moja wersja dla każdego, kto jej potrzebuje.
źródło
Dlaczego nie po prostu przetłumaczyć swojego identyfikatora na ciąg? Potrzebujesz tylko funkcji, która odwzorowuje cyfrę między, powiedzmy, 0 a 61 na pojedynczą literę (wielkie / małe litery) lub cyfrę. Następnie zastosuj to, aby utworzyć, powiedzmy, 4-literowe kody, a otrzymasz 14,7 miliona adresów URL.
źródło
Oto przyzwoita funkcja kodowania adresów URL dla PHP ...
źródło
Nie wiem, czy ktokolwiek uzna to za przydatne - jest to raczej metoda „hack n slash”, ale jest prosta i działa dobrze, jeśli chcesz tylko określonych znaków.
źródło
Czy celowo ominąłeś O, 0 i ja?
Właśnie stworzyłem klasę PHP opartą na rozwiązaniu Ryana.
źródło
Spójrz na https://hashids.org/ jest to oprogramowanie typu open source w wielu językach.
Ich strona przedstawia niektóre pułapki innych podejść.
źródło
Oto, czego używam:
Jest bardzo szybki i może zająć długie liczby całkowite.
źródło
W przypadku podobnego projektu, aby uzyskać nowy klucz, uruchamiam funkcję otoki wokół losowego generatora ciągów, który wywołuje generator, dopóki nie otrzymam ciągu, który nie był jeszcze używany w mojej tablicy mieszającej. Ta metoda zwolni, gdy przestrzeń nazw zacznie się zapełniać, ale jak już powiedziałeś, nawet z zaledwie 6 znakami, masz mnóstwo przestrzeni nazw do pracy.
źródło
Mam wariant problemu, polegający na tym, że przechowuję strony internetowe wielu różnych autorów i muszę zapobiegać wykrywaniu stron przez zgadywanie. Więc moje krótkie adresy URL dodają kilka dodatkowych cyfr do ciągu Base-62 dla numeru strony. Te dodatkowe cyfry są generowane z informacji w samym rekordzie strony i zapewniają, że tylko 1 na 3844 adresów URL jest prawidłowy (przy założeniu 2-cyfrowej wartości Base-62). Ogólny opis można zobaczyć na stronie http://mgscan.com/MBWL .
źródło
Bardzo dobra odpowiedź, stworzyłem implementację bjf w Golang:
Hostowane na github: https://github.com/xor-gate/go-bjf
źródło
źródło
Wdrożenie w Scali:
Przykład testu z testem Scala:
źródło
Funkcja oparta na klasie Xeoncross
źródło
Oto implementacja Node.js, która prawdopodobnie jest bit.ly. generuje wysoce losowy ciąg siedmiu znaków.
Wykorzystuje krypto Node.js do generowania wysoce losowego zestawu znaków 25 zamiast losowego wybierania siedmiu znaków.
źródło
Moja wersja Python 3
źródło
Aby uzyskać wysokiej jakości rozwiązanie Node.js / JavaScript, zobacz moduł id-shortener , który został dokładnie przetestowany i był używany w produkcji od miesięcy.
Zapewnia efektywne skrócenie identyfikatora / adresu URL wspierane przez pamięć wtykową domyślnie ustawioną na Redis , a nawet można dostosować zestaw znaków krótkiego identyfikatora i określić, czy skrócenie jest idempotentne . Jest to ważne rozróżnienie, które nie wszystkie skracacze URL biorą pod uwagę.
W odniesieniu do innych odpowiedzi tutaj, moduł ten implementuje doskonale przyjętą powyżej odpowiedź Marcela Jackwertha.
Rdzeń rozwiązania zapewnia następujący fragment Redis Lua :
źródło
Dlaczego po prostu nie wygenerować losowego ciągu i dołączyć go do podstawowego adresu URL? Jest to bardzo uproszczona wersja robienia tego w języku C # .
Następnie po prostu dodaj ciąg losowy do baseURL:
Pamiętaj, że jest to bardzo uproszczona wersja robienia tego i jest możliwe, że metoda RandomString może tworzyć duplikaty ciągów. W produkcji należy wziąć pod uwagę zduplikowane ciągi, aby mieć zawsze unikalny adres URL. Mam kod, który bierze pod uwagę zduplikowane ciągi, poprzez zapytanie do tabeli bazy danych, którą mógłbym udostępnić, jeśli ktoś jest zainteresowany.
źródło
Oto moje początkowe przemyślenia i można zrobić więcej przemyśleń lub przeprowadzić symulację, aby sprawdzić, czy działa ona dobrze, czy konieczna jest poprawa:
Moja odpowiedź to zapamiętanie długiego adresu URL w bazie danych i użycie identyfikatora
0
do9999999999999999
(lub jak dużej liczby jest potrzebny).Ale identyfikator 0
9999999999999999
może być problemem, ponieważA
-Z
a
-z
0
-9
_
i-
)0
do9999999999999999
równomiernie, hakerzy mogą odwiedzać ich w tej kolejności i wiedzieć, jakie adresy URL wysyłają sobie nawzajem, więc może to być problem z prywatnościąMożemy to zrobić:
0
na999
jednego serwera, Serwer A, więc teraz Serwer A ma 1000 takich identyfikatorów. Więc jeśli 20 lub 200 serwerów ciągle chce nowych identyfikatorów, nie musi ciągle pytać o każdy nowy identyfikator, a raczej pytać raz o 1000 identyfikatorów000...00000001
staje się10000...000
, tak, że po przekonwertowaniu do base64, to będzie nierównomiernie zwiększanie numerów ID za każdym razem.0xD5AA96...2373
(jak tajny klucz), a niektóre bity zostaną odwrócone. (za każdym razem, gdy tajny klucz ma włączony 1 bit, odwróci bit identyfikatora). To sprawi, że identyfikatory będą jeszcze trudniejsze do odgadnięcia i będą wyglądać bardziej losowoZgodnie z tym schematem pojedynczy serwer, który przydziela identyfikatory, może tworzyć identyfikatory, podobnie jak 20 lub 200 serwerów żądających przydzielenia identyfikatorów. Serwer alokujący musi użyć blokady / semafora, aby zapobiec otrzymaniu tej samej partii przez dwa serwery żądające (lub jeśli przyjmuje jedno połączenie na raz, to już rozwiązuje problem). Dlatego nie chcemy, aby linia (kolejka) była zbyt długa, aby mogła czekać na przydział. Dlatego przydzielenie 1000 lub 10000 na raz może rozwiązać problem.
źródło