wake-up-neo.net

Wie erstelle ich einen URL-Shortener?

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

Anstelle von "abcdef" kann es auch eine beliebige andere Zeichenfolge mit sechs Zeichen geben, die a-z, A-Z and 0-9 enthält. Das macht 56 ​​~ 57 Milliarden mögliche Zeichenfolgen.

Mein Ansatz:

Ich habe eine Datenbanktabelle mit drei Spalten:

  1. id, integer, auto-increment
  2. long, string, die vom Benutzer eingegebene lange URL
  3. kurz, Zeichenfolge, die verkürzte URL (oder nur die sechs Zeichen)

Ich würde dann die lange URL in die Tabelle einfügen. Dann würde ich den Auto-Inkrement-Wert für "id" auswählen und einen Hash davon erstellen. Dieser Hash sollte dann als "short" eingefügt werden. Aber welche Art von Hash soll ich bauen? Hash-Algorithmen wie MD5 erzeugen zu lange Strings. Ich denke, ich verwende diese Algorithmen nicht. Ein selbstgebauter Algorithmus wird auch funktionieren.

Meine Idee:

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

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.

Das könnte so lange wiederholt werden, bis die Zahl nicht mehr teilbar ist. Denken Sie, dass dies ein guter Ansatz ist? Hast du eine bessere Idee?

Aufgrund des anhaltenden Interesses an diesem Thema habe ich eine effiziente Lösung für GitHub veröffentlicht mit Implementierungen für JavaScript , PHP , Python und Java . Fügen Sie Ihre Lösungen hinzu, wenn Sie möchten:)

634
caw

Ich würde Ihren Ansatz "Zahl in Zeichenfolge konvertieren" fortsetzen. Sie werden jedoch feststellen, dass Ihr vorgeschlagener Algorithmus fehlschlägt, wenn Ihre ID eine Primzahl und größer als 52 ist.

Theoretischer Hintergrund

Sie benötigen eine bijektive Funktion f . Dies ist notwendig, damit Sie eine Umkehrfunktion g ('abc') = 123 für Ihr f (finden können. 123) = 'abc' Funktion. Das heisst:

  • Es darf kein x1, x2 (mit x1 ≠ x2) geben, das f (x1) = f ( x2) ,
  • und für jedes y muss es möglich sein, ein x zu finden, damit f (x) = y .

So konvertieren Sie die ID in eine verkürzte URL

  1. Denken Sie an ein Alphabet, das wir verwenden möchten. In deinem Fall ist das [a-zA-Z0-9]. Es enthält 62 Buchstaben .
  2. Nehmen Sie einen automatisch generierten, eindeutigen numerischen Schlüssel (zum Beispiel den automatisch inkrementierten id einer MySQL-Tabelle).

    Für dieses Beispiel verwende ich 12510 (125 mit einer Basis von 10).

  3. Jetzt müssen Sie 125 konvertieren10 bis X62 (Basis 62).

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

    Dies erfordert die Verwendung von Ganzzahldivision und Modulo. Ein Pseudocode-Beispiel:

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

    Ordnen Sie nun die Indizes 2 und 1 Ihrem Alphabet zu. So könnte Ihr Mapping (zum Beispiel mit einem Array) aussehen:

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

    Mit 2 → c und 1 → b erhalten Sie cb62 als verkürzte URL.

    http://shor.ty/cb
    

So lösen Sie eine verkürzte URL in die ursprüngliche ID auf

Das Gegenteil ist noch einfacher. Sie machen einfach eine umgekehrte Suche in Ihrem Alphabet.

  1. e9a62 wird in "4., 61. und 0. Buchstabe des Alphabets" aufgelöst.

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

  2. Suchen Sie nun Ihren Datenbankeintrag mit WHERE id = 19158 und leiten Sie ihn weiter.

Beispielimplementierungen (bereitgestellt von Kommentatoren)

779

Warum solltest du einen Hash verwenden?

Sie können einfach eine einfache Übersetzung Ihres Auto-Inkrement-Werts in einen alphanumerischen Wert verwenden. Sie können dies leicht tun, indem Sie eine Basiskonvertierung verwenden. Angenommen, der Zeichenbereich (A-Z, a-z, 0-9 usw.) besteht aus 40 Zeichen, konvertieren Sie die ID in eine Zahl zur Basis 40 und verwenden Sie die Zeichen als Ziffern.

54
shoosh
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;
    }   
}
48
richard

Keine Antwort auf Ihre Frage, aber ich würde keine verkürzten URLs verwenden, bei denen zwischen Groß- und Kleinschreibung unterschieden wird. Sie sind schwer zu merken, in der Regel nicht lesbar (viele Schriften sind 1 und 1, 0 und O und andere Zeichen sehr ähnlich, so dass es nahezu unmöglich ist, den Unterschied zu erkennen) und fehleranfällig. Versuchen Sie, nur Groß- oder Kleinschreibung zu verwenden.

Versuchen Sie auch, ein Format zu verwenden, in dem Sie die Zahlen und Zeichen in einer vordefinierten Form mischen. Es gibt Studien, die zeigen, dass sich Menschen eine Form besser merken als andere (denken Sie an Telefonnummern, bei denen die Nummern in einer bestimmten Form gruppiert sind). Versuchen Sie etwas wie num-char-char-num-char-char. Ich weiß, dass dies die Kombinationen verringert, besonders wenn Sie keine Groß- und Kleinschreibung haben, aber es wäre nützlicher und daher nützlicher.

32
Ash

Mein Ansatz: Nimm die Datenbank-ID und dann Base36 Encode it . Ich würde NICHT sowohl Groß- als auch Kleinbuchstaben verwenden, da dies das Übertragen dieser URLs über das Telefon zu einem Albtraum macht, aber Sie könnten die Funktion natürlich leicht erweitern, um ein Base-62-En/Decoder zu sein.

28
Michael Stum

Hier ist meine Klasse PHP 5.

<?php
class Bijective
{
    public $dictionary = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

    public function __construct()
    {
        $this->dictionary = str_split($this->dictionary);
    }

    public function encode($i)
    {
        if ($i == 0)
        return $this->dictionary[0];

        $result = '';
        $base = count($this->dictionary);

        while ($i > 0)
        {
            $result[] = $this->dictionary[($i % $base)];
            $i = floor($i / $base);
        }

        $result = array_reverse($result);

        return join("", $result);
    }

    public function decode($input)
    {
        $i = 0;
        $base = count($this->dictionary);

        $input = str_split($input);

        foreach($input as $char)
        {
            $pos = array_search($char, $this->dictionary);

            $i = $i * $base + $pos;
        }

        return $i;
    }
}
8
Xeoncross

Eine Lösung für Node.js und MongoDB

Da wir das Format kennen, das MongoDB verwendet, um eine neue ObjectId mit 12 Bytes zu erstellen.

  • ein 4-Byte-Wert, der die Sekunden seit der Unix-Epoche darstellt,
  • eine 3-Byte-Rechnerkennung,
  • eine 2-Byte-Prozess-ID
  • ein 3-Byte-Zähler (in Ihrem Computer), der mit einem zufälligen Wert beginnt.

Beispiel (ich wähle eine zufällige Reihenfolge) a1b2c3d4e5f6g7h8i9j1k2l

  • a1b2c3d4 stellt die Sekunden seit der Unix-Epoche dar,
  • 4e5f6g7 repräsentiert die Maschinenkennung,
  • h8i9 repräsentiert die Prozess-ID
  • j1k2l3 repräsentiert den Zähler, beginnend mit einem zufälligen Wert.

Da der Zähler eindeutig ist, wenn wir die Daten auf demselben Computer speichern, können wir ihn ohne Zweifel abrufen, dass er dupliziert wird.

Die kurze URL ist also der Zähler und hier ist ein Codeausschnitt, der davon ausgeht, dass Ihr Server ordnungsgemäß ausgeführt wird.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// Create a schema
const shortUrl = new Schema({
    long_url: { type: String, required: true },
    short_url: { type: String, required: true, unique: true },
  });
const ShortUrl = mongoose.model('ShortUrl', shortUrl);

// The user can request to get a short URL by providing a long URL using a form

app.post('/shorten', function(req ,res){
    // Create a new shortUrl */
    // The submit form has an input with longURL as its name attribute.
    const longUrl = req.body["longURL"];
    const newUrl = ShortUrl({
        long_url : longUrl,
        short_url : "",
    });
    const shortUrl = newUrl._id.toString().slice(-6);
    newUrl.short_url = shortUrl;
    console.log(newUrl);
    newUrl.save(function(err){
        console.log("the new URL is added");
    })
});
6
Firas Omrane

Sie könnten die gesamte URL hashen, aber wenn Sie nur die ID verkürzen möchten, tun Sie das, was marcel vorgeschlagen hat. Ich habe diese Python Implementierung geschrieben:

https://Gist.github.com/778542

4
bhelx

C # -Version:

public class UrlShortener 
{
    private static String ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    private static int    BASE     = 62;

    public static String encode(int num)
    {
        StringBuilder sb = new StringBuilder();

        while ( num > 0 )
        {
            sb.Append( ALPHABET[( num % BASE )] );
            num /= BASE;
        }

        StringBuilder builder = new StringBuilder();
        for (int i = sb.Length - 1; i >= 0; i--)
        {
            builder.Append(sb[i]);
        }
        return builder.ToString(); 
    }

    public static int decode(String str)
    {
        int num = 0;

        for ( int i = 0, len = str.Length; i < len; i++ )
        {
            num = num * BASE + ALPHABET.IndexOf( str[(i)] ); 
        }

        return num;
    }   
}
4
user1477388
// simple approach

$original_id = 56789;

$shortened_id = base_convert($original_id, 10, 36);

$un_shortened_id = base_convert($shortened_id, 36, 10);
3
phirschybar
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

Hier ist meine Version für wen auch immer.

2

Wenn Sie das Rad nicht neu erfinden möchten ... http://lilurl.sourceforge.net/

2
Alister Bulman

Ich inkrementiere weiterhin eine Ganzzahlsequenz pro Domain in der Datenbank und verwende Hashids , um die Ganzzahl in einen URL-Pfad zu kodieren.

static hashids = Hashids(salt = "my app rocks", minSize = 6)

Ich habe ein Skript ausgeführt, um zu sehen, wie lange es dauert, bis die Zeichenlänge erschöpft ist. Für sechs Zeichen kann es 164,916,224 Verknüpfungen ausführen und dann bis zu sieben Zeichen. Bitly verwendet sieben Zeichen. Unter fünf Zeichen kommt mir das komisch vor.

Hashids kann den URL-Pfad zurück zu einer Ganzzahl decodieren, aber eine einfachere Lösung besteht darin, den gesamten Kurzlink sho.rt/ka8ds3 als Primärschlüssel zu verwenden.

Hier ist das vollständige Konzept:

function addDomain(domain) {
    table("domains").insert("domain", domain, "seq", 0)
}

function addURL(domain, longURL) {
    seq = table("domains").where("domain = ?", domain).increment("seq")
    shortURL = domain + "/" + hashids.encode(seq)
    table("links").insert("short", shortURL, "long", longURL)
    return shortURL
}

// GET /:hashcode
function handleRequest(req, res) {
    shortURL = req.Host + "/" + req.param("hashcode")
    longURL = table("links").where("short = ?", shortURL).get("long")
    res.redirect(301, longURL)
}
2
AJcodez

Haben Sie absichtlich O, 0 und i weggelassen?

Ich habe gerade eine PHP -Klasse erstellt, die auf Ryans Lösung basiert.

<?php

    $shorty = new App_Shorty();

    echo 'ID: ' . 1000;
    echo '<br/> Short link: ' . $shorty->encode(1000);
    echo '<br/> Decoded Short Link: ' . $shorty->decode($shorty->encode(1000));


    /**
     * A Nice shorting class based on Ryan Charmley's suggestion see the link on Stack Overflow below.
     * @author Svetoslav Marinov (Slavi) | http://WebWeb.ca
     * @see http://stackoverflow.com/questions/742013/how-to-code-a-url-shortener/10386945#10386945
     */
    class App_Shorty {
        /**
         * Explicitly omitted: i, o, 1, 0 because they are confusing. Also use only lowercase ... as
         * dictating this over the phone might be tough.
         * @var string
         */
        private $dictionary = "abcdfghjklmnpqrstvwxyz23456789";
        private $dictionary_array = array();

        public function __construct() {
            $this->dictionary_array = str_split($this->dictionary);
        }

        /**
         * Gets ID and converts it into a string.
         * @param int $id
         */
        public function encode($id) {
            $str_id = '';
            $base = count($this->dictionary_array);

            while ($id > 0) {
                $rem = $id % $base;
                $id = ($id - $rem) / $base;
                $str_id .= $this->dictionary_array[$rem];
            }

            return $str_id;
        }

        /**
         * Converts /abc into an integer ID
         * @param string
         * @return int $id
         */
        public function decode($str_id) {
            $id = 0;
            $id_ar = str_split($str_id);
            $base = count($this->dictionary_array);

            for ($i = count($id_ar); $i > 0; $i--) {
                $id += array_search($id_ar[$i - 1], $this->dictionary_array) * pow($base, $i - 1);
            }
            return $id;
        }
    }
?>
1

Hier ist eine anständige URL-Codierungsfunktion für PHP ...

// From http://snipplr.com/view/22246/base62-encode--decode/
private function base_encode($val, $base=62, $chars='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
    $str = '';
    do {
        $i = fmod($val, $base);
        $str = $chars[$i] . $str;
        $val = ($val - $i) / $base;
    } while($val > 0);
    return $str;
}
1
Simon East

Ich weiß nicht, ob dies für jemanden von Nutzen ist - es ist eher eine Hack-n-Slash-Methode, sie ist jedoch einfach und funktioniert gut, wenn Sie nur bestimmte Zeichen verwenden möchten.

$dictionary = "abcdfghjklmnpqrstvwxyz23456789";
$dictionary = str_split($dictionary);

// Encode
$str_id = '';
$base = count($dictionary);

while($id > 0) {
    $rem = $id % $base;
    $id = ($id - $rem) / $base;
    $str_id .= $dictionary[$rem];
}


// Decode
$id_ar = str_split($str_id);
$id = 0;

for($i = count($id_ar); $i > 0; $i--) {
    $id += array_search($id_ar[$i-1], $dictionary) * pow($base, $i - 1);
} 
1
Ryan Charmley

Funktion basierend auf der Xeoncross-Klasse

function shortly($input){
$dictionary = ['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','0','1','2','3','4','5','6','7','8','9'];
if($input===0)
    return $dictionary[0];
$base = count($dictionary);
if(is_numeric($input)){
    $result = [];
    while($input > 0){
        $result[] = $dictionary[($input % $base)];
        $input = floor($input / $base);
    }
    return join("", array_reverse($result));
}
$i = 0;
$input = str_split($input);
foreach($input as $char){
    $pos = array_search($char, $dictionary);
    $i = $i * $base + $pos;
}
return $i;
}
0
Luis Neighbur
/**
 * <p>
 *     Integer to character and vice-versa
 * </p>
 *  
 */
public class TinyUrl {

    private final String characterMap = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    private final int charBase = characterMap.length();

    public String covertToCharacter(int num){
        StringBuilder sb = new StringBuilder();

        while (num > 0){
            sb.append(characterMap.charAt(num % charBase));
            num /= charBase;
        }

        return sb.reverse().toString();
    }

    public int covertToInteger(String str){
        int num = 0;
        for(int i = 0 ; i< str.length(); i++)
            num += characterMap.indexOf(str.charAt(i)) * Math.pow(charBase , (str.length() - (i + 1)));

        return num;
    }
}

class TinyUrlTest{

    public static void main(String[] args) {
        TinyUrl tinyUrl = new TinyUrl();
        int num = 122312215;
        String url = tinyUrl.covertToCharacter(num);
        System.out.println("Tiny url:  " + url);
        System.out.println("Id: " + tinyUrl.covertToInteger(url));
    }
}
0

Implementierung in Scala:

class Encoder(alphabet: String) extends (Long => String) {

  val Base = alphabet.size

  override def apply(number: Long) = {
    def encode(current: Long): List[Int] = {
      if (current == 0) Nil
      else (current % Base).toInt :: encode(current / Base)
    }
    encode(number).reverse
      .map(current => alphabet.charAt(current)).mkString
  }
}

class Decoder(alphabet: String) extends (String => Long) {

  val Base = alphabet.size

  override def apply(string: String) = {
    def decode(current: Long, encodedPart: String): Long = {
      if (encodedPart.size == 0) current
      else decode(current * Base + alphabet.indexOf(encodedPart.head),encodedPart.tail)
    }
    decode(0,string)
  }
}

Testbeispiel mit Scala test:

import org.scalatest.{FlatSpec, Matchers}

class DecoderAndEncoderTest extends FlatSpec with Matchers {

  val Alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

  "A number with base 10" should "be correctly encoded into base 62 string" in {
    val encoder = new Encoder(Alphabet)
    encoder(127) should be ("cd")
    encoder(543513414) should be ("KWGPy")
  }

  "A base 62 string" should "be correctly decoded into a number with base 10" in {
    val decoder = new Decoder(Alphabet)
    decoder("cd") should be (127)
    decoder("KWGPy") should be (543513414)
  }

}
0
adrift

Meine Python 3-Version

base_list = list("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
base = len(base_list)

def encode(num: int):
    result = []
    if num == 0:
        result.append(base_list[0])

    while num > 0:
        result.append(base_list[num % base])
        num //= base

    print("".join(reversed(result)))

def decode(code: str):
    num = 0
    code_list = list(code)
    for index, code in enumerate(reversed(code_list)):
        num += base_list.index(code) * base ** index
    print(num)

if __== '__main__':
    encode(341413134141)
    decode("60FoItT")
0
wyx

Sehr gute Antwort, ich habe eine Golang-Implementierung des Bjf erstellt:

package bjf

import (
    "math"
    "strings"
    "strconv"
)

const alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

func Encode(num string) string {
    n, _ := strconv.ParseUint(num, 10, 64)
    t := make([]byte, 0)

    /* Special case */
    if n == 0 {
        return string(alphabet[0])
    }

    /* Map */
    for n > 0 {
        r := n % uint64(len(alphabet))
        t = append(t, alphabet[r])
        n = n / uint64(len(alphabet))
    }

    /* Reverse */
    for i, j := 0, len(t) - 1; i < j; i, j = i + 1, j - 1 {
        t[i], t[j] = t[j], t[i]
    }

    return string(t)
}

func Decode(token string) int {
    r := int(0)
    p := float64(len(token)) - 1

    for i := 0; i < len(token); i++ {
        r += strings.Index(alphabet, string(token[i])) * int(math.Pow(float64(len(alphabet)), p))
        p--
    }

    return r
}

Gehostet bei github: https://github.com/xor-gate/go-bjf

0
Jerry Jacobs

Warum übersetzen Sie nicht einfach Ihre ID in einen String? Sie benötigen lediglich eine Funktion, die eine Ziffer zwischen beispielsweise 0 und 61 einem einzelnen Buchstaben (Groß-/Kleinschreibung) oder einer Ziffer zuordnet. Wenden Sie dies an, um beispielsweise 4-Buchstaben-Codes zu erstellen, und Sie haben 14,7 Millionen abgedeckte URLs.

0
cr333

Ich habe eine Variante des Problems, indem ich Webseiten von vielen verschiedenen Autoren speichere und die Entdeckung von Seiten durch Rätselraten verhindern muss. Daher fügen meine kurzen URLs der Base-62-Zeichenfolge für die Seitenzahl ein paar zusätzliche Ziffern hinzu. Diese zusätzlichen Ziffern werden aus Informationen im Seitendatensatz selbst generiert und stellen sicher, dass nur 1 von 3844 URLs gültig ist (unter der Annahme einer zweistelligen Base-62). Eine Kurzbeschreibung finden Sie unter http://mgscan.com/MBWL .

0
Graham

Hier ist eine Node.js-Implementierung, die wahrscheinlich bit.ly ist. generieren Sie eine sehr zufällige siebenstellige Zeichenfolge.

Es verwendet Node.js Krypto, um einen höchst zufälligen Zeichensatz zu generieren, anstatt sieben Zeichen zufällig auszuwählen.

var crypto = require("crypto");
exports.shortURL = new function () {
    this.getShortURL = function () {
        var sURL = '',
            _Rand = crypto.randomBytes(25).toString('hex'),
            _base = _Rand.length;
        for (var i = 0; i < 7; i++)
            sURL += _Rand.charAt(Math.floor(Math.random() * _Rand.length));
        return sURL;
    };
}
0
Hafiz Arslan

Das benutze ich:

# Generate a [0-9a-zA-Z] string
ALPHABET = map(str,range(0, 10)) + map(chr, range(97, 123) + range(65, 91))

def encode_id(id_number, alphabet=ALPHABET):
    """Convert an integer to a string."""
    if id_number == 0:
        return alphabet[0]

    alphabet_len = len(alphabet) # Cache

    result = ''
    while id_number > 0:
        id_number, mod = divmod(id_number, alphabet_len)
        result = alphabet[mod] + result

    return result

def decode_id(id_string, alphabet=ALPHABET):
    """Convert a string to an integer."""
    alphabet_len = len(alphabet) # Cache
    return sum([alphabet.index(char) * pow(alphabet_len, power) for power, char in enumerate(reversed(id_string))])

Es ist sehr schnell und kann lange ganze Zahlen dauern.

0

Eine hochwertige Lösung für Node.js/JavaScript finden Sie im id-shortener -Modul, das gründlich getestet und seit Monaten in der Produktion eingesetzt wird.

Es bietet einen effizienten ID-/URL-Shortener, der durch einsteckbaren Speicher mit der Standardeinstellung Redis unterstützt wird. Sie können sogar Ihren kurzen ID-Zeichensatz anpassen und festlegen, ob eine Kürzung erfolgen soll oder nicht idempotent . Dies ist ein wichtiger Unterschied, der nicht bei allen URL-Kürzern berücksichtigt wird.

In Bezug auf andere Antworten hier implementiert dieses Modul die von Marcel Jackwerth akzeptierte Antwort oben.

Den Kern der Lösung bildet das folgende Redis Lua Snippet :

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
fisch2

Um einen neuen Schlüssel für ein ähnliches Projekt zu erhalten, erstelle ich eine Wrapper-Funktion um einen Zufalls-String-Generator , der den Generator aufruft, bis ich einen String erhalte, der noch nicht in meiner Hash-Tabelle verwendet wurde. Diese Methode verlangsamt sich, sobald Ihr Namensraum voll wird, aber wie Sie bereits sagten, haben Sie auch mit nur 6 Zeichen genügend Zeit, um mit dem Namensraum zu arbeiten.

0
Joel Berger