704 Stimmen

Wie erstelle ich einen URL-Verkürzer?

Ich möchte einen URL-Verkürzungsdienst erstellen, bei dem Sie eine lange URL in ein Eingabefeld eingeben können und der Dienst die URL auf "http://www.example.org/abcdef" verkürzt.

Anstelle von "abcdef" kann jeder andere String mit sechs Zeichen stehen, der a-z, A-Z und 0-9 enthält. Das ergibt etwa 56~57 Milliarden mögliche Zeichenfolgen.

Mein Ansatz:

Ich habe eine Datenbanktabelle mit drei Spalten:

  1. id, integer, auto-inkrement
  2. long, string, die lange URL, die der Benutzer eingegeben hat
  3. short, string, die verkürzte URL (oder nur die sechs Zeichen)

Dann würde ich die lange URL in die Tabelle einfügen. Anschließend würde ich den Wert des Auto-Inkrement-Feldes "id" auswählen und daraus einen Hash erstellen. Dieser Hash sollte dann als "short" eingefügt werden. Aber welche Art von Hash sollte ich erstellen? Hash-Algorithmen wie MD5 erzeugen zu lange Zeichenfolgen. Diese Algorithmen verwende ich nicht, denke ich. Ein selbst entwickelter Algorithmus würde ebenfalls funktionieren.

Meine Idee:

Für "http://www.google.de/" erhalte ich die Auto-Inkrement-ID 239472. Dann führe ich die folgenden Schritte aus:

short = '';
if durch 2 teilbar, füge "a"+das Ergebnis zu short hinzu
if durch 3 teilbar, füge "b"+das Ergebnis zu short hinzu
... bis ich Teiler von a-z und A-Z habe.

Das könnte wiederholt werden, bis die Zahl nicht mehr teilbar ist. Glauben Sie, dass dies ein guter Ansatz ist? Haben Sie eine bessere Idee?

<em>Aufgrund des anhaltenden Interesses an diesem Thema habe ich eine effiziente Lösung auf GitHub veröffentlicht, mit Implementierungen für <a href="https://github.com/delight-im/ShortURL" rel="noreferrer">JavaScript</a>, <a href="https://github.com/delight-im/ShortURL/blob/master/PHP/ShortURL.php" rel="noreferrer">PHP</a>, <a href="https://github.com/delight-im/ShortURL/blob/master/Python/shorturl.py" rel="noreferrer">Python</a> und <a href="https://github.com/delight-im/ShortURL/blob/master/Java/ShortURL.java" rel="noreferrer">Java</a>. Fügen Sie Ihre Lösungen hinzu, wenn Sie möchten :)</em>

5 Stimmen

@gudge Der Zweck dieser Funktionen besteht darin, dass sie eine inverse Funktion haben. Dies bedeutet, dass Sie sowohl die Funktionen encode() als auch decode() haben können. Die Schritte sind daher: (1) URL in der Datenbank speichern (2) Eindeutige Zeilen-ID für diese URL aus der Datenbank abrufen (3) Ganzzahlige ID in kurzen String mit encode() umwandeln, z.B. von 273984 zu f5a4 (4) Verwenden Sie den kurzen String (z.B. f4a4) in Ihren freigegebenen URLs (5) Beim Empfang einer Anfrage für einen kurzen String (z.B. 20a8) decodieren Sie den String in eine Ganzzahl-ID mit decode() (6) Suchen Sie die URL in der Datenbank für die angegebene ID. Zur Umwandlung verwenden Sie: github.com/delight-im/ShortURL

0 Stimmen

@ Marco, was ist der Sinn, den Hash in der Datenbank zu speichern?

3 Stimmen

@MaksimVi. Wenn Sie eine invertierbare Funktion haben, gibt es keine. Wenn Sie eine Einweg-Hash-Funktion hätten, gäbe es eine.

865voto

Marcel Jackwerth Punkte 51964

Ich würde deinen Ansatz, Zahlen in Strings umzuwandeln, weiterverfolgen. Allerdings wirst du feststellen, dass dein vorgeschlagenes Algorithmus versagt, wenn deine ID eine Primzahl größer als 52 ist.

Theoretischer Hintergrund

Du brauchst eine Bijektive Funktion f. Dies ist notwendig, damit du eine Umkehrfunktion g('abc') = 123 für deine Funktion f(123) = 'abc' finden kannst. Das bedeutet:

  • Es darf keine x1, x2 (mit x1 x2) geben, für die f(x1) = f(x2) gilt,
  • und für jedes y musst du ein x finden können, so dass f(x) = y gilt.

Wie man die ID in eine gekürzte URL umwandelt

  1. Denke an ein Alphabet, das du verwenden möchtest. In deinem Fall wäre das [a-zA-Z0-9]. Es enthält 62 Buchstaben.

  2. Nimm einen automatisch generierten, eindeutigen numerischen Schlüssel (zum Beispiel die automatisch inkrementierte id einer MySQL-Tabelle).

    Für dieses Beispiel werde ich 12510 (125 zur Basis 10) verwenden.

  3. Jetzt musst du 12510 in X62 (Basis 62) umwandeln.

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

    Dafür musst du Ganzzahldivision und Modulo verwenden. Ein Pseudocode-Beispiel:

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

    Ordne jetzt die Indices 2 und 1 deinem Alphabet zu. So könnte deine Zuordnung (mit einem Array zum Beispiel) aussehen:

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

    Mit 2 c und 1 b erhältst du cb62 als gekürzte URL.

    http://shor.ty/cb

Wie man eine gekürzte URL in die ursprüngliche ID auflöst

Die Umkehrung ist noch einfacher. Du machst einfach eine Rückwärtssuche in deinem Alphabet.

  1. e9a62 wird als "4. , 61. und 0. Buchstabe im Alphabet" aufgelöst werden.

    e9a62 = [4,61,0] = 4×622 + 61×621 + 0×620 = 1915810

  2. Finde jetzt deinen Datenbankeintrag mit WHERE id = 19158 und führe die Weiterleitung durch.

Beispielimplementierungen (bereitgestellt von Kommentatoren)

20 Stimmen

Vergessen Sie nicht, die URLs auf schädlichen JavaScript-Code zu bereinigen! Denken Sie daran, dass JavaScript in einer URL base64-codiert werden kann, daher reicht es nicht aus, einfach nach 'javascript' zu suchen.

0 Stimmen

@apphacker: Könnten Sie bitte kurz erklären, wie man sanitizes? Ich dachte, es würde ausreichen, die strip_tags() Funktion in PHP zu verwenden. Oder sagen Sie mir, wenn das nicht kurz erklärt werden kann, dann poste ich es als eine neue Frage hier.

4 Stimmen

Eine Funktion muss bijektiv (injektiv und surjektiv) sein, um eine Umkehrfunktion zu haben.

57voto

shoosh Punkte 73374

Warum würdest du einen Hash verwenden wollen?

Du kannst einfach eine einfache Übersetzung deines Auto-Inkrement-Werts in einen alphanumerischen Wert verwenden. Das kannst du leicht machen, indem du eine Basisumrechnung verwendest. Angenommen dein Zeichenraum (A-Z, a-z, 0-9, etc.) hat 62 Zeichen, konvertiere die ID in eine Basis-40 Zahl und nutze die Zeichen als Ziffern.

14 Stimmen

Abgesehen davon, dass A-Z, a-z und 0-9 = 62 Zeichen, nicht 40 sind, liegen Sie genau richtig.

0 Stimmen

Danke! Soll ich dann das Basis-62-Alphabet verwenden? de.wikipedia.org/wiki/Base_62 Wie kann ich jedoch die IDs in eine Basis-62-Nummer umwandeln?

0 Stimmen

Mit einem Basisumwandlungsalgorithmus natürlich - de.wikipedia.org/wiki/Basisumwandlung#Wechsel_der_Basis

52voto

Stradivariuz Punkte 2463
public class UrlShortener {
    private static final String ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    private static final int BASE = ALPHABET.length();

    public static String encode(int num) {
        StringBuilder sb = new StringBuilder();
        while ( num > 0 ) {
            sb.append( ALPHABET.charAt( num % BASE ) );
            num /= BASE;
        }
        return sb.reverse().toString();   
    }

    public static int decode(String str) {
        int num = 0;
        for ( int i = 0; i < str.length(); i++ )
            num = num * BASE + ALPHABET.indexOf(str.charAt(i));
        return num;
    }   
}

0 Stimmen

Ich finde die Idee wirklich gut, das einzige Problem, das ich damit habe, ist, dass ich die Variable num in der Decode-Funktion immer außerhalb des Bereichs erhalte (auch für long), hast du eine Idee, wie man es zum Laufen bringen kann? Oder ist es nur theoretisch?

0 Stimmen

@user1322801: Vermutlich versuchen Sie, etwas zu entschlüsseln, das wesentlich größer ist als das, was die Codierfunktion tatsächlich verarbeiten kann. Sie könnten etwas mehr daraus machen, wenn Sie alle "ints" in BigInteger umwandeln, aber es sei denn, Sie haben mehr als 9223372036854775807 Indizes, sollte long wahrscheinlich ausreichen.

3 Stimmen

Darf ich wissen, was die Bedeutung von Umkehrung ist? zB sb.reverse().toString();

33voto

Ash Punkte 689

Nicht eine Antwort auf Ihre Frage, aber ich würde keine Groß- und Kleinschreibung sensitiven verkürzten URLs verwenden. Sie sind schwer zu merken, meistens unleserlich (viele Schriftarten stellen 1 und l, 0 und O und andere Zeichen sehr ähnlich dar, dass sie fast unmöglich zu unterscheiden sind) und fehleranfällig. Versuchen Sie, nur Klein- oder Großbuchstaben zu verwenden.

Versuchen Sie außerdem, ein Format zu haben, in dem Sie die Zahlen und Zeichen in einer vordefinierten Form mischen. Studien zeigen, dass Menschen dazu neigen, eine Form besser zu merken als andere (denken Sie an Telefonnummern, wo die Zahlen in einer bestimmten Form gruppiert sind). Versuchen Sie etwas wie z.B. num-char-char-num-char-char. Ich weiß, dass dies die Kombinationsmöglichkeiten verringern wird, besonders wenn Sie keine Groß- und Kleinbuchstaben haben, aber es wäre benutzerfreundlicher und daher nützlicher.

2 Stimmen

Vielen Dank, sehr gute Idee. Daran habe ich noch nicht gedacht. Es ist klar, dass es davon abhängt, um welche Art von Nutzung es geht, ob das sinnvoll ist oder nicht.

19 Stimmen

Es wird kein Problem sein, wenn die Leute die Kurz-URLs streng kopieren und einfügen.

2 Stimmen

Der Zweck von Kurz-URLs besteht nicht darin, dass sie leicht zu merken oder auszusprechen sind. Es geht nur um das Klicken oder Kopieren/Einfügen.

30voto

Michael Stum Punkte 172055

Mein Ansatz: Nehmen Sie die Datenbank-ID, dann Base36 Encode sie. Ich würde NICHT sowohl Groß- ALS AUCH Kleinbuchstaben verwenden, denn das macht die Übertragung dieser URLs über das Telefon zu einem Albtraum, aber Sie könnten die Funktion natürlich leicht erweitern, um ein Basis-62-En-/Decoder zu sein.

0 Stimmen

Vielen Dank, du hast recht. Ob du 2.176.782.336 Möglichkeiten oder 56.800.235.584 hast, ist das Gleiche: Beide werden ausreichen. Also werde ich die Basis-36-Codierung verwenden.

0 Stimmen

Es mag offensichtlich sein, aber hier ist etwas PHP-Code, auf den in Wikipedia verwiesen wird, um eine Base64-Kodierung in PHP durchzuführen tonymarston.net/php-mysql/converter.html

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X