मैं एक URL शॉर्टनर कैसे बनाऊं?


667

मैं एक URL शॉर्टनर सेवा बनाना चाहता हूं जहां आप एक लंबे URL को इनपुट फ़ील्ड में लिख सकते हैं और सेवा URL को छोटा कर देती है "http://www.example.org/abcdef " में ।

" abcdef" के बजाय छह वर्णों वाला कोई अन्य स्ट्रिंग हो सकता है a-z, A-Z and 0-9। यह 56 ~ 57 बिलियन संभव तार बनाता है।

मेरा दृष्टिकोण:

मेरे पास एक डेटाबेस तालिका है जिसमें तीन कॉलम हैं:

  1. आईडी, पूर्णांक, ऑटो-वेतन वृद्धि
  2. उपयोगकर्ता द्वारा दर्ज किया गया लंबा, स्ट्रिंग, लंबा URL
  3. छोटा, स्ट्रिंग, छोटा URL (या सिर्फ छह अक्षर)

फिर मैं लंबे URL को तालिका में सम्मिलित करूँगा। तब मैं " id" के लिए ऑटो-इन्क्रीमेंट वैल्यू चुनूँगा और इसका एक हैश बनाऊंगा। यह हैश तब डाला जाना चाहिए "short " के । लेकिन मुझे किस प्रकार के हैश का निर्माण करना चाहिए? एमडी 5 जैसे हैश एल्गोरिदम बहुत लंबे तार पैदा करते हैं। मैं इन एल्गोरिदम का उपयोग नहीं करता, मुझे लगता है। एक स्व-निर्मित एल्गोरिथ्म भी काम करेगा।

मेरा विचार:

" http://www.google.de/" के लिए मुझे ऑटो-इंक्रीमेंट आईडी मिलता है 239472। फिर मैं निम्नलिखित कदम उठाता हूं:

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.

यह दोहराया जा सकता है जब तक कि संख्या किसी भी अधिक विभाज्य नहीं है। क्या आपको लगता है कि यह एक अच्छा तरीका है? क्या आपके पास एक बेहतर विचार है?

इस विषय में जारी रुचि के कारण, मैंने GitHub के लिए एक कुशल समाधान प्रकाशित किया है , जावास्क्रिप्ट , PHP , पायथन और जावा के लिए कार्यान्वयन के साथ । अपने समाधान जोड़ें अगर आप की तरह :)


5
@gudge उन कार्यों का बिंदु यह है कि उनका उलटा कार्य होता है। इसका मतलब है कि आपके पास कार्य encode()और decode()कार्य दोनों हो सकते हैं । चरणों इसलिए कर रहे हैं: (1) सहेजें यूआरएल डेटाबेस में (2) के साथ छोटे स्ट्रिंग के लिए डेटाबेस (3) Convert पूर्णांक आईडी से उस URL के लिए अद्वितीय पंक्ति आईडी प्राप्त करें encode(), जैसे 273984करने के लिए f5a4(4) कम स्ट्रिंग (उदाहरण के लिए उपयोग करें f4a4) में sharable URL (5) छोटी स्ट्रिंग (जैसे 20a8) के लिए अनुरोध प्राप्त करते समय , स्ट्रिंग को पूर्णांक आईडी के साथ डिकोड करें decode()(6) दिए गए आईडी के लिए डेटाबेस में URL देखें। रूपांतरण के लिए, उपयोग करें: github.com/delight-im/ShortURL
caw

@ मार्को, डेटाबेस में हैश के भंडारण की बात क्या है?
मक्सीम वी।

3
@MaksimVi। यदि आपके पास एक उलटा कार्य है, तो कोई नहीं है। यदि आपके पास एक-तरफ़ा हैश फ़ंक्शन है, तो एक होगा।
जूल

1
यदि हम URL को छोटा करने के लिए सरल CRC32 एल्गोरिथ्म का उपयोग करते हैं तो यह गलत होगा? हालांकि टकराव की बहुत संभावना नहीं है (एक CRC32 आउटपुट आमतौर पर 8 वर्ण लंबा होता है और जो हमें 30 मिलियन से अधिक संभावनाएं देता है) यदि एक उत्पन्न CRC32 आउटपुट पहले ही उपयोग किया गया था और डेटाबेस में पाया गया था, तो हम लंबे URL को एक यादृच्छिक संख्या के साथ नमक कर सकते हैं जब तक हमें CRC32 आउटपुट नहीं मिल जाता, जो मेरे डेटाबेस में अद्वितीय है। एक सरल समाधान के लिए यह कितना बुरा या अलग या बदसूरत होगा?
रकीब

जवाबों:


816

मैं आपके "कन्वर्ट नंबर टू स्ट्रिंग" एप्रोच को जारी रखूंगा। हालांकि, आपको एहसास होगा कि आपका प्रस्तावित एल्गोरिथ्म विफल हो जाता है यदि आपकी आईडी एक प्रमुख है और 52 से अधिक है

सैद्धांतिक पृष्ठभूमि

आपको एक Bijective Function f की आवश्यकता है । यह आवश्यक है ताकि आप अपने f (123) = 'abc' फ़ंक्शन के लिए उलटा फ़ंक्शन जी ('एबीसी') = 123 पा सकें । इसका मतलब है की:

  • कोई X1, x2 (X1 2 x2 के साथ) नहीं होना चाहिए जो f (X1) = f (x2) बना देगा ,
  • और हर y के लिए आपको एक x खोजने में सक्षम होना चाहिए ताकि f (x) = y हो

ID को छोटा URL में कैसे बदलें

  1. एक वर्णमाला के बारे में सोचो जिसका हम उपयोग करना चाहते हैं। आपके मामले में, यही [a-zA-Z0-9]। इसमें 62 अक्षर हैं
  2. एक ऑटो-जनरेटेड, यूनिक न्यूमेरिकल की ( idउदाहरण के लिए MySQL टेबल का ऑटो-इन्क्रिमेटेड ) लें।

    इस उदाहरण के लिए, मैं 125 10 ( 10 के आधार के साथ 125) का उपयोग करूंगा ।

  3. अब आपको 125 10 को एक्स 62 (बेस 62) में बदलना है ।

    125 10 = 2 × 62 1 + 1 × 62 0 =[2,1]

    इसके लिए पूर्णांक विभाजन और मोडुलो के उपयोग की आवश्यकता होती है। एक छद्म कोड उदाहरण:

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

    अब अपने वर्णमाला के सूचक 2 और 1 को मैप करें । यह है कि आपकी मैपिंग (उदाहरण के लिए एक सरणी के साथ) जैसी दिख सकती है:

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

    2 → c और 1 → b के साथ, आपको छोटा URL के रूप में cb 62 प्राप्त होगा ।

    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और रीडायरेक्ट करें।

उदाहरण कार्यान्वयन (टिप्पणीकारों द्वारा प्रदान)


18
दुर्भावनापूर्ण जावास्क्रिप्ट कोड के लिए URL साफ़ करना न भूलें! याद रखें कि जावास्क्रिप्ट को एक URL में base64 इनकोड किया जा सकता है, इसलिए सिर्फ 'जावास्क्रिप्ट' की खोज करना पर्याप्त नहीं है ।j
ब्योर्न

3
एक व्युत्क्रम के लिए एक फ़ंक्शन बायजेक्टिव (इंजेक्टिव और सर्जेक्टिव) होना चाहिए ।
गुमबो

57
विचार के लिए भोजन, यह url में दो वर्ण चेकसम जोड़ने के लिए उपयोगी हो सकता है। यह आपके सिस्टम में सभी यूआरएल के प्रत्यक्ष पुनरावृत्ति को रोक देगा। F (चेकसम (id)% (62 ^ 2)) + f (id) = url_id
koblas

6
जहाँ तक url को sanitizing करने की बात है, आप जिन समस्याओं का सामना करने जा रहे हैं, उनमें से एक है स्पैम फ़िल्टर से बचने के लिए अपनी URL का उपयोग करने के लिए आपकी सेवा का उपयोग करने वाले स्पैमर्स। आपको या तो ज्ञात अच्छे अभिनेताओं के लिए सेवा को सीमित करने की आवश्यकता है, या लंबे समय के यूआरएल के लिए स्पैम फ़िल्टरिंग लागू करना होगा। अन्यथा आप स्पैमर्स द्वारा दुर्व्यवहार किया जाएगा।
एडवर्ड फॉक

74
Base62 एक बुरा विकल्प हो सकता है क्योंकि इसमें f * शब्द उत्पन्न करने की क्षमता है (उदाहरण के लिए, 3792586=='F_ck'_ के स्थान पर यू के साथ)। इसे कम करने के लिए मैं कुछ वर्णों को छोड़ दूंगा जैसे कि u / U।
पाउलो स्कार्डिन

56

आप हैश का उपयोग क्यों करना चाहेंगे?

आप बस अपने ऑटो-इंक्रीमेंट मान का एक सरल अनुवाद अल्फ़ान्यूमेरिक मान का उपयोग कर सकते हैं। आप कुछ आधार रूपांतरण का उपयोग करके आसानी से कर सकते हैं। आप वर्ण स्थान कहते हैं (AZ, az, 0-9, आदि) में 40 वर्ण हैं, आईडी को आधार -40 संख्या में परिवर्तित करें और अंकों के रूप में वर्णों का उपयोग करें।


13
इस तथ्य से तय होता है कि AZ, az और 0-9 = 62 वर्ण, 40 नहीं, आप निशान पर सही हैं।
इवान टेरन

धन्यवाद! क्या मुझे आधार -62 वर्णमाला का उपयोग करना चाहिए? en.wikipedia.org/wiki/Base_62 लेकिन मैं आईडी को आधार -62 नंबर में कैसे बदल सकता हूं?
caw

बेस कन्वर्जन एल्गोरिथ्म
ऑफ़कोर्स

2
"आप एक हैश का उपयोग क्यों करना चाहते हैं?" के बारे में, ऑटो-इन्क्रीमेंट पर आधारित एक आधार रूपांतरण अनुक्रमिक URL बनाने जा रहा है, इसलिए आपको ऐसे लोगों के साथ सहज होना होगा जो अन्य लोगों के छोटे URL को "ब्राउज़" करने में सक्षम हों। सही?
एंड्रयू कोलेसन

2
पर्याप्त संसाधनों और समय के साथ आप किसी भी URL को छोटा करने वाली सेवा के सभी URL को "ब्राउज़" कर सकते हैं।
21

51
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;
    }   
}

मैं वास्तव में इस विचार को पसंद करता हूं, मेरे पास एकमात्र समस्या यह है कि मैं डिकोड फ़ंक्शन में सीमा चर को सीमा से बाहर रखता हूं (यहां तक ​​कि लंबे समय तक), क्या आपके पास कोई विचार है कि इसे कैसे काम करना है? या यह केवल सैद्धांतिक है?
user1322801

@ user1322801: संभवतः आप उस चीज़ को डिकोड करने का प्रयास कर रहे हैं जो एनकोड फ़ंक्शन वास्तव में संभाल सकता है, उससे कहीं अधिक बड़ा था। यदि आप सभी "इन्ट्स" को बिगइन्टेगर में बदल देते हैं, तो आप इससे कुछ अधिक लाभ प्राप्त कर सकते हैं, लेकिन जब तक आपको> 9223372036854775807 सूचकांक नहीं मिलेंगे, तब तक शायद पर्याप्त होना चाहिए।
biggusjimmus

2
क्या मुझे पता है कि पलटने का क्या महत्व है? यानी sb.reverse () .String ();
डॉटनेट डिकोडर

यह 62 ^ 62 = 1.7 ट्रिलियन?
नूह टोनी

33

आपके प्रश्न का उत्तर नहीं है, लेकिन मैं केस-संवेदी संक्षिप्त URL का उपयोग नहीं करूंगा। उन्हें याद रखना मुश्किल है, आमतौर पर अपठनीय (कई फोंट 1 और एल, 0 और ओ और अन्य वर्णों को बहुत समान रूप से प्रस्तुत करते हैं कि वे अंतर बताने के लिए असंभव हैं) और सर्वथा त्रुटि प्रवण हैं। केवल निचले या ऊपरी मामले का उपयोग करने का प्रयास करें।

इसके अलावा, एक प्रारूप रखने की कोशिश करें जहां आप संख्याओं और वर्णों को पूर्वनिर्धारित रूप में मिलाते हैं। ऐसे अध्ययन हैं जो बताते हैं कि लोग दूसरों की तुलना में एक रूप को बेहतर याद करते हैं (फोन नंबर सोचें, जहां संख्या एक विशिष्ट रूप में समूहीकृत होती है)। संख्या-चार-चार-संख्या-चार-चार जैसी कुछ कोशिश करें। मुझे पता है कि यह संयोजन को कम करेगा, खासकर यदि आपके पास ऊपरी और निचला मामला नहीं है, लेकिन यह अधिक उपयोगी और इसलिए उपयोगी होगा।


2
धन्यवाद, बहुत अच्छा विचार है। मैंने अभी तक इसके बारे में नहीं सोचा है। यह स्पष्ट है कि यह इस तरह के उपयोग पर निर्भर करता है कि यह समझ में आता है या नहीं।
caw

19
यह एक मुद्दा नहीं होगा अगर लोग छोटे यूआरएल को सख्ती से कॉपी-पेस्ट कर रहे हैं।
एडवर्ड फॉक

2
शॉर्ट यूआरएल का उद्देश्य यादगार या बोलने में आसान नहीं है। केवल क्लिक या कॉपी / पेस्ट है।
ह्यूगो नोगीरा

हाँ, मुझे लगा कि छोटा URL केवल लोगों को इसे सूचीबद्ध करने या ईमेल करने के लिए है और इसलिए यह छोटा है और कुछ URL जैसे 200 अक्षरों को नहीं लेगा, इसलिए मामला कोई समस्या नहीं है
nonopolarity

29

मेरा दृष्टिकोण: डेटाबेस आईडी लें, फिर Base36 इसे एनकोड करें । मैं ऊपरी और निचले दोनों अक्षरों का उपयोग नहीं करूंगा, क्योंकि यह उन यूआरएल को टेलीफोन पर एक बुरे सपने को प्रसारित करता है, लेकिन आप निश्चित रूप से फ़ंक्शन को आधार 62 एन / डिकोडर होने के लिए आसानी से बढ़ा सकते हैं।


धन्यवाद, आप सही कह रहे हैं। चाहे आपके पास 2,176,782,336 संभावनाएं हों या 56,800,235,584, यह समान है: दोनों पर्याप्त होंगे। इसलिए मैं बेस 36 एनकोडिंग का उपयोग करूंगा।
कांव-कांव

यह स्पष्ट हो सकता है, लेकिन यहाँ कुछ PHP कोड को संदर्भित किया गया है wikipedia में php tonymarston.net/php-mysql/converter.html
रयान व्हाइट

8

यहाँ मेरी 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;
    }
}

6

एक Node.js और MongoDB समाधान

चूंकि हमें पता है कि MongoDB 12 बाइट्स के साथ एक नया ObjectId बनाने के लिए प्रारूप का उपयोग करता है।

  • यूनिक्स युग के बाद से सेकंड का प्रतिनिधित्व करने वाला 4-बाइट मान,
  • एक 3-बाइट मशीन पहचानकर्ता,
  • एक 2-बाइट प्रक्रिया आईडी
  • एक 3-बाइट काउंटर (आपकी मशीन में), एक यादृच्छिक मूल्य के साथ शुरू होता है।

उदाहरण (मैं एक यादृच्छिक क्रम चुनता हूं ) a1b2c3d4e5f6g7h8i9j1k2b3

  • यूनिक्स युग के बाद से a1b2c3d4 सेकंड का प्रतिनिधित्व करता है,
  • 4e5f6g7 मशीन पहचानकर्ता का प्रतिनिधित्व करता है,
  • h8i9 प्रक्रिया आईडी का प्रतिनिधित्व करता है
  • j1k2l3 एक यादृच्छिक मूल्य के साथ शुरू होने वाले काउंटर का प्रतिनिधित्व करता है।

चूंकि काउंटर अद्वितीय होगा यदि हम उसी मशीन में डेटा संग्रहीत कर रहे हैं तो हम इसे बिना किसी संदेह के प्राप्त कर सकते हैं कि यह डुप्लिकेट होगा।

तो छोटा URL काउंटर होगा और यहां एक कोड स्निपेट माना गया है कि आपका सर्वर ठीक से चल रहा है।

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");
    })
});

1
एक RDBMS एक बिना sql / की-वैल्यू स्टोर से बेहतर कैसे होगा?
kjs3

@ kjs3 हाँ आप सही हैं, क्योंकि अन्य तालिकाओं के साथ कोई संबंध नहीं हैं, RDBMS की कोई आवश्यकता नहीं है और एक प्रमुख मूल्य की दुकान तेज होगी।
फिरास ओमरान

4

C # संस्करण:

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

आप पूरे URL को हैश कर सकते हैं, लेकिन यदि आप केवल आईडी को छोटा करना चाहते हैं, तो जैसा कि marcel ने सुझाव दिया है, करें। मैंने इसे पायथन कार्यान्वयन लिखा है:

https://gist.github.com/778542


4

मैं डेटाबेस में प्रति डोमेन एक पूर्णांक अनुक्रम बढ़ाता हूं और पूर्णांक को URL पथ में एन्कोड करने के लिए हैशिड्स का उपयोग करता हूं

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

मैंने एक स्क्रिप्ट चलाई कि यह देखने में कितना समय लगता है जब तक कि चरित्र की लंबाई समाप्त नहीं हो जाती। छह वर्णों के लिए यह 164,916,224लिंक कर सकता है और फिर सात वर्णों तक जाता है। सात वर्णों का थोड़ा उपयोग करता है। पांच पात्रों के तहत मुझे अजीब लगता है।

हैशिड्स URL पथ को एक पूर्णांक में वापस डिकोड कर सकते हैं लेकिन एक सरल समाधान sho.rt/ka8ds3एक प्राथमिक कुंजी के रूप में संपूर्ण लघु लिंक का उपयोग करना है ।

यहाँ पूर्ण अवधारणा है:

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)
}

3

यदि आप पहिये का पुनः आविष्कार नहीं करना चाहते हैं ... http://lilurl.sourceforge.net/


1
"क्षमा करें, ऐसा लगता है कि स्पैमर इसे मिल गया है। इसके बजाय टाइगरेल का प्रयास करें।"
ताकेशिन

डेमो साइट के लिए। स्रोत कोड अभी भी Sourceforge से डाउनलोड करने योग्य है।
एलिस्टर बुलमैन

3
// simple approach

$original_id = 56789;

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

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

2
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

यहाँ मेरे संस्करण के लिए जिसे यह चाहिए।


1

क्यों न सिर्फ अपनी आईडी को स्ट्रिंग में ट्रांसलेट किया जाए? आपको बस एक फ़ंक्शन की आवश्यकता होती है जो एक अक्षर (ऊपरी / निचले मामले) या अंक के बीच, 0 और 61 के बीच के अंक को दर्शाता है। फिर 4-अक्षर कोड बनाने, कहने के लिए इसे लागू करें, और आपको 14.7 मिलियन URL मिल गए हैं।


सरल सोच के लिए +1। वास्तव में यह उतना आसान है। मैंने सिर्फ एक उत्तर पोस्ट किया है जो वास्तव में ऐसा कर रहा है। मेरे पास कुछ उत्पादन कोड हैं जो यह सुनिश्चित करने के लिए डेटाबेस से सवाल करते हैं कि कोई डुप्लिकेट स्ट्रिंग नहीं है और सब कुछ अद्वितीय है।
एंड्रयू रीज़

1

यहाँ PHP के लिए एक अच्छा URL एन्कोडिंग फ़ंक्शन है ...

// 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

पता नहीं अगर किसी को यह उपयोगी लगेगा - यह एक 'हैक एन स्लैश' पद्धति से अधिक है, फिर भी सरल है और अच्छी तरह से काम करता है यदि आप केवल विशिष्ट वर्ण चाहते हैं।

$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

क्या आपने ओ, 0, और i को उद्देश्य से छोड़ा था?

मैंने सिर्फ रयान के समाधान के आधार पर एक PHP वर्ग बनाया।

<?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

Https://hashids.org/ पर नज़र डालें तो यह खुला स्रोत है और कई भाषाओं में है।

उनका पृष्ठ अन्य दृष्टिकोणों की कुछ कमियों को रेखांकित करता है।


0

यही है वह जो मेरे द्वारा उपयोग किया जाता है:

# 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))])

यह बहुत तेज़ है और लंबे पूर्णांक ले सकता है।


0

इसी तरह की परियोजना के लिए, एक नई कुंजी प्राप्त करने के लिए, मैं एक यादृच्छिक स्ट्रिंग जनरेटर के चारों ओर एक रैपर फ़ंक्शन करता हूं जो जनरेटर को कॉल करता है जब तक मुझे एक स्ट्रिंग नहीं मिलती है जो पहले से ही मेरे हैशटेबल में उपयोग नहीं की गई है। एक बार जब आपका नाम स्थान पूर्ण होने लगता है, तो यह विधि धीमी हो जाएगी, लेकिन जैसा कि आपने कहा है, यहां तक ​​कि केवल 6 वर्णों के साथ, आपके पास काम करने के लिए बहुत सारे नाम स्थान हैं।


क्या इस दृष्टिकोण ने आपके लिए लंबे समय तक काम किया है?
क्रिस

सच कहूँ तो, मुझे नहीं पता कि मैं किस प्रोजेक्ट का जिक्र कर रहा था :-P
जोएल बर्जर

0

मेरे पास समस्या का एक प्रकार है, जिसमें मैं कई अलग-अलग लेखकों से वेब पेज संग्रहीत करता हूं और अनुमान लगाने से पृष्ठों की खोज को रोकने की आवश्यकता होती है। इसलिए मेरे छोटे URL पृष्ठ संख्या के लिए बेस -62 स्ट्रिंग में कुछ अतिरिक्त अंक जोड़ते हैं। ये अतिरिक्त अंक पेज रिकॉर्ड में ही जानकारी से उत्पन्न होते हैं और वे यह सुनिश्चित करते हैं कि 3844 URL में केवल 1 ही मान्य है (2 अंकों का बेस -62 मानकर)। आप http://mgscan.com/MBWL पर एक रूपरेखा विवरण देख सकते हैं ।


0

बहुत अच्छा जवाब, मैंने bjf का गोलंग कार्यान्वयन बनाया है:

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
}

Github पर होस्ट किया गया: https://github.com/xor-gate/go-bjf


0
/**
 * <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

स्काला में कार्यान्वयन:

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)
  }
}

स्काला टेस्ट के साथ परीक्षा उदाहरण:

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

Xeoncross Class में स्थित फंक्शन

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

यहाँ एक Node.js कार्यान्वयन है जो बिट होने की संभावना है। एक अत्यधिक यादृच्छिक सात-वर्ण स्ट्रिंग उत्पन्न करें।

यह बेतरतीब ढंग से सात वर्णों का चयन करने के बजाय एक अत्यधिक यादृच्छिक 25 चारसेट उत्पन्न करने के लिए Node.js क्रिप्टो का उपयोग करता है।

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;
    };
}

आपको "bit.ly" से क्या मतलब है ?
पीटर मोर्टेंसन

0

मेरा पायथन 3 संस्करण

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 __name__ == '__main__':
    encode(341413134141)
    decode("60FoItT")

0

एक गुणवत्ता Node.js / जावास्क्रिप्ट समाधान के लिए, आईडी-शॉर्टनर मॉड्यूल देखें, जिसका अच्छी तरह से परीक्षण किया गया है और महीनों तक उत्पादन में उपयोग किया गया है।

यह एक कुशल आईडी / URL shortener के लिए दोषी प्लगेबल भंडारण द्वारा समर्थित प्रदान करता है Redis , और तुम भी अपने छोटे आईडी वर्ण सेट अनुकूलित कर सकते हैं और चाहे या नहीं छोटा है idempotent । यह एक महत्वपूर्ण अंतर है जो सभी यूआरएल शॉर्टर्स को ध्यान में नहीं रखता है।

अन्य उत्तरों के संबंध में, यह मॉड्यूल ऊपर दिए गए मार्सेल जैकवर्थ के उत्कृष्ट स्वीकृत उत्तर को लागू करता है।

समाधान का मूल निम्नलिखित 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

क्यों न केवल एक यादृच्छिक स्ट्रिंग उत्पन्न करें और इसे आधार 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);
}

तो बस आधार में यादृच्छिक स्ट्रिंग जोड़ने के लिए:

string tinyURL = baseUrl + RandomString(5);

याद रखें कि यह ऐसा करने का एक बहुत ही सरल संस्करण है और यह संभव है कि रैंडमस्ट्रिंग विधि डुप्लिकेट स्ट्रिंग्स बना सकती है। उत्पादन में आप डुप्लिकेट स्ट्रिंग्स के लिए ध्यान रखना चाहेंगे ताकि यह सुनिश्चित हो सके कि आपके पास हमेशा एक अद्वितीय URL होगा। मेरे पास कुछ कोड है जो डेटाबेस तालिका को क्वेरी करके डुप्लिकेट स्ट्रिंग्स के लिए खाता है जिसे मैं साझा कर सकता हूं अगर किसी को दिलचस्पी है।


0

यह मेरे प्रारंभिक विचार हैं, और अधिक सोच-विचार किया जा सकता है, या कुछ सिमुलेशन यह देखने के लिए किया जा सकता है कि क्या यह अच्छी तरह से काम करता है या किसी सुधार की आवश्यकता है:

मेरा उत्तर डेटाबेस में लंबे URL को याद रखना है, और आईडी 0का उपयोग 9999999999999999(या फिर बड़ी संख्या में आवश्यक है)।

लेकिन आईडी 0 9999999999999999एक मुद्दा हो सकता है, क्योंकि

  1. यदि हम हेक्साडेसिमल या बेस 62 या बेस 64 का उपयोग करते हैं तो यह कम हो सकता है। (बेस 64 यू ट्यूब की तरह ही A- Z a- z 0- 9 _और -)
  2. अगर यह से बढ़ जाती है 0के लिए 9999999999999999समान रूप से है, तो हैकर्स इसी क्रम में उन पर जाते हैं और पता यूआरएल लोग एक-दूसरे क्या भेज रहे हैं कर सकते हैं, तो यह एक गोपनीयता मुद्दा हो सकता है

हम यह कर सकते हैं:

  1. एक सर्वर को आवंटित किया 0है999 तो अब सर्वर एक ऐसे आईडी के 1000 है, के लिए एक सर्वर, सर्वर एक। इसलिए यदि 20 या 200 सर्वर लगातार नई आईडी चाहते हैं, तो उसे प्रत्येक नई आईडी के लिए पूछते रहना नहीं है, बल्कि 1000 आईडी से एक बार पूछना है
  2. आईडी 1 के लिए, उदाहरण के लिए, बिट्स को उल्टा करें। इसलिए 000...00000001बन जाता है 10000...000, ताकि जब इसे बेस 64 में बदल दिया जाए , तो यह हर बार गैर-समान रूप से बढ़ती आईडी होगी।
  3. अंतिम आईडी के लिए बिट्स फ्लिप करने के लिए XOR का उपयोग करें। उदाहरण के लिए, XOR 0xD5AA96...2373(एक गुप्त कुंजी की तरह), और कुछ बिट्स फ़्लिप किए जाएंगे। (जब भी गुप्त कुंजी में 1 बिट होता है, तो वह आईडी को थोड़ा सा फ्लिप करेगा)। यह आईडी को और अधिक यादृच्छिक रूप से अनुमान लगाने और प्रदर्शित करने के लिए कठिन बना देगा

इस योजना के बाद, आईडी आवंटित करने वाला एकल सर्वर आईडी बना सकता है, और इसलिए 20 या 200 सर्वर आईडी के आवंटन का अनुरोध कर सकते हैं। आवंटन करने वाले सर्वर को दो अनुरोध करने वाले सर्वर को एक ही बैच प्राप्त करने से रोकने के लिए एक लॉक / सेमाफोर का उपयोग करना पड़ता है (या यदि यह एक बार में एक कनेक्शन स्वीकार कर रहा है, तो यह पहले से ही समस्या का हल करता है)। इसलिए हम नहीं चाहते कि आवंटन प्राप्त करने की प्रतीक्षा में लाइन (कतार) बहुत लंबी हो। इसीलिए एक बार में 1000 या 10000 आवंटित करने से समस्या हल हो सकती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.