İnsan tarafından okunabilir / kullanılabilir, kısa ancak benzersiz kimlikler oluşturma


89
  • Günde> 1000 ancak <10000 yeni kayıt işlemesi gerekir

  • GUID / UUID'ler, otomatik artış numaraları vb. Kullanılamaz.

  • İdeal olarak 5 veya 6 karakter uzunluğunda olmalı, elbette alfa olabilir

  • Varsa mevcut, iyi bilinen algoları yeniden kullanmak ister

Orada bir şey var mı?


Neden otomatik artırımlı bir INT veya BIGINT kullanmıyorsunuz? Muhtemelen en okunabilir olanıdır ve hacmi kolayca idare edebilir.
Malk

yukarıdaki Q'ya göre, maksimum 5/6 karakterde tutmaya ve günde 9999 yeni kaydı desteklemeye çalışıyor
Kumar

@Kumar - Bir günde 9999'dan fazla kayda ihtiyacınız olursa ne olur? Önerdiğiniz çözüm makul görünmüyor.
ChaosPandion

@ChaosPandion: Bunların muhtemelen katı sınırlardan ziyade kaba yük / trafik tahminleri olduğunu düşünüyorum. Günlük işlemlerin sayısına neden keyfi bir sınır koymak istediğinizden emin değilim.
Paul Sasik

64 tabanına kodlayabilir ve kullanabilirsin. Bunu bundan daha küçük hale getirip yine de okunabilir karakterler kullanabileceğinizden emin değilim. Ancak 64 tabanının 32 tabanından çok daha az okunabilir olduğunu iddia ediyorum çünkü çoğu karaktere fazladan bir niteleyici eklemeyi gerektiriyor (büyük f, küçük o, küçük o'ya karşılık sadece f, oo).
Malk

Yanıtlar:


122

Base 62, tinyurl ve bit.ly tarafından kısaltılmış URL'ler için kullanılır. "Benzersiz", insan tarafından okunabilir kimlikler oluşturmak için iyi anlaşılmış bir yöntemdir. Elbette, benzersizliği sağlamak için oluşturulan kimlikleri kaydetmeniz ve oluşturma sırasında kopyaları kontrol etmeniz gerekecektir. (Cevabın altındaki koda bakın)

Base 62 benzersizlik ölçümleri

62 tabanındaki 5 karakter size 62 ^ 5 benzersiz kimlik verir = 916.132.832 (~ 1 milyar) Günde 10.000 kimlikte 91.000'den fazla gün boyunca uygun olacaksınız

62 tabanındaki 6 karakter size 62 ^ 6 benzersiz kimlik verir = 56.800.235.584 (56+ milyar) Günde 10.000 kimlik ile 5 milyondan fazla gün boyunca iyi olacaksınız

Temel 36 benzersizlik ölçümleri

6 karakter size 36 ^ 6 benzersiz kimlik verir = 2.176.782.336 (2+ milyar)

7 karakter size 36 ^ 7 benzersiz kimlik verir = 78,364,164,096 (78+ milyar)

Kod:

public void TestRandomIdGenerator()
{
    // create five IDs of six, base 62 characters
    for (int i=0; i<5; i++) Console.WriteLine(RandomIdGenerator.GetBase62(6));

    // create five IDs of eight base 36 characters
    for (int i=0; i<5; i++) Console.WriteLine(RandomIdGenerator.GetBase36(8));
}

public static class RandomIdGenerator 
{
    private static char[] _base62chars = 
        "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
        .ToCharArray();

    private static Random _random = new Random();

    public static string GetBase62(int length) 
    {
        var sb = new StringBuilder(length);

        for (int i=0; i<length; i++) 
            sb.Append(_base62chars[_random.Next(62)]);

        return sb.ToString();
    }       

    public static string GetBase36(int length) 
    {
        var sb = new StringBuilder(length);

        for (int i=0; i<length; i++) 
            sb.Append(_base62chars[_random.Next(36)]);

        return sb.ToString();
    }
}

Çıktı:

z5KyMg
wd4SUp
uSzQtH
UPrGAT
UIf2IS

QCF9GNM5
0UV3TFSS
3MG91VKP
7NTRF10T
AJK3AJU7

3
harika görünüyor, büyük / küçük harfe duyarlı olmayan herhangi bir şey?
Kumar

2
Büyük / küçük harfe duyarlı olmaktan kaçınmak istiyorsanız, 36 tabanını kullanabilirsiniz: codeproject.com/Articles/10619/Base-36-type-for-NET-C, ancak bu kadar çok permütasyonu 62 tabanı olarak elde etmek için, daha fazla karakter kullanmanız gerekir. İD. Bu bir değiş tokuş. Veya alfanın yanı sıra başka karakterler kullanmayı deneyebilirsiniz, ancak bu kullanıcılar için çirkinleşir.
Paul Sasik

2
burada stackoverflow.com/questions/9543892/… & çok teşekkürler
Kumar

12
Bir düşünce. Belki de kazara küfür kelimelerinin oluşmasını önlemek için ünlüleri çıkarın. Özellikle de halka açıksa.
Damien Sawyer

4
Bunu nerede kullandığınıza bağlı olarak (özellikle insanların kodları okuması ve yeniden girmesi bekleniyorsa), sıkça karışan karakterleri göz önünde bulundurmaktan kaldırmayı düşünebilirsiniz: 0 / O ve I / l / 1. Bu, bazı durumlarda iyi bir yazı tipi seçimiyle hafifletilebilir, ancak OP'nin bunu kontrol edip edemeyeceği sorusundan anlayamıyorum.
GrandOpener

18

Herhangi bir sayıyı (örn. DB Kimliği) bir dizeye (salt kullanarak) dönüştüren http://hashids.org/ ' i öneririm .

Bu dizginin kodunun tekrar numaraya çözülmesini sağlar. Böylece, onu veritabanında saklamanıza gerek kalmaz.

JavaScript, Ruby, Python, Java, Scala, PHP, Perl, Swift, Clojure, Objective-C, C, C ++ 11, Go, Erlang, Lua, Elixir, ColdFusion, Groovy, Kotlin, Nim, VBA, CoffeeScript ve Node.js ve .NET için.


1
Teklifinize benzer başka seçenekler sunabilir misiniz? - - Çok ilginç. PostgreSQL'de buna benzer varsayılan seçenekler olup olmadığını bilmek istiyorum.
Léo Léopold Hertz 준영

1
İşte bunun .NET sürümü, ancak veritabanında saklamaya gerek kalmadan nasıl çalıştığını açıklayabilir misiniz? Girdi olarak sayı vermeden ve tuz olmadan sadece benzersiz rasgele üretebilir miyim?
Shaiju T

@Slawa NET için karma gibi bir şeye ihtiyacım var, ancak son karma db'de sabit uzunlukta bir sütunda depolanacak, bu her zaman maksimum N uzunluğunda bir karma oluştur demek mümkün mü?
Anon Dev

6

OP ile benzer gereksinimlerim vardı. Mevcut kitaplıklara baktım ama çoğu rastgeleliğe dayanıyor ve bunu istemedim. Rastlantısal olmayan ve hala çok kısa olan hiçbir şey bulamadım ... Bu yüzden , Flickr'ın kullandığı tekniğe dayanarak kendi yöntemimi yuvarladım , ancak daha az koordinasyon gerektirecek ve daha uzun süre çevrimdışı kalmasına izin verecek şekilde değiştirildim.

Kısacası:

  • Merkezi bir sunucu, her biri 32 kimlikten oluşan kimlik blokları yayınlar
  • Yerel kimlik üreteci, her talep edildiğinde bir kimlik oluşturmak için bir kimlik bloğu havuzu tutar. Havuz azaldığında, tekrar doldurmak için sunucudan daha fazla ID bloğu alır.

Dezavantajları:

  • Merkezi koordinasyon gerektirir
  • Kimlikler aşağı yukarı tahmin edilebilirdir (normal DB kimliklerinden daha azdır, ancak rastgele değildirler)

Avantajlar

  • 53 bit dahilinde kalır (tam sayılar için Javascript / PHP maksimum boyut)
  • çok kısa kimlikler
  • Baz 36, insanların okuması, yazması ve telaffuz etmesi çok kolay kodlandı
  • Kimlikler, sunucuyla tekrar iletişime geçmeden önce çok uzun bir süre yerel olarak oluşturulabilir (havuz ayarlarına bağlı olarak)
  • Teorik olarak çarpışma şansı yok

Hem istemci tarafı için bir Javascript kitaplığı hem de bir Java EE sunucusu uygulaması yayınladım. Sunucuları diğer dillerde uygulamak da kolay olmalıdır.

İşte projeler:

suid - Kısa ve öz olan Dağıtılmış Hizmete Özgü Kimlikler

suid-server-java - Java EE teknoloji yığını için Suid-sunucu uygulaması.

Her iki kütüphane de liberal bir Creative Commons açık kaynak lisansı altında mevcuttur. Bunun, kısa benzersiz kimlikler arayan başka birine yardımcı olabileceğini umuyoruz.


Lütfen stackoverflow.com/a/29372036/54964'ü teklifinizle karşılaştırır suidmısınız?
Léo Léopold Hertz 준영

1
Rastgele sayılara dayanmaktadır. Aslında oldukça harika. Ancak kimlikleriniz olabildiğince kısa olmayacak. Numaralandırmaya 1'den başlamak için SUID yazdım, böylece son derece kısa kimliklerle başlayacaksınız . 3 veya 4 karakter düşünün. Artı, gerçekten kısa olanlardan başlamak dışında (kabaca) artımlı olarak sıralanan kimliklere sahip olmanın başka güzel avantajları da vardır.
Stijn de Witt

3

Birkaç yıl önce geliştirdiğim bir uygulama için bu sorunu çözdüğümde 36 tabanını kullandım . İnsan tarafından okunabilir, makul ölçüde benzersiz bir numara üretmem gerekiyordu (zaten mevcut takvim yılı içinde). Zamanı, cari yılın 1 Ocak gece yarısından itibaren milisaniye cinsinden kullanmayı seçtim (böylece her yıl, zaman damgaları çoğaltılabilir) ve bunu 36 temel sayıya dönüştürdüm. Geliştirilmekte olan sistem ölümcül bir sorunla karşılaştıysa, web arayüzü aracılığıyla bir son kullanıcıya görüntülenen temel 36 sayısını (7 karakter) oluşturdu ve daha sonra karşılaşılan sorunu (ve numarayı) bir teknik destek personeline (kim daha sonra günlüklerde yığın izlemenin başladığı noktayı bulmak için kullanabilir). 56af42g7 gibi bir sayı2016-01-21T15: 34: 29.933-08: 00 gibi bir zaman damgası veya 5f0d3e0c-da96-11e5-b5d2-0a1d41d68578 gibi rastgele bir UUID yerine bir kullanıcının okuması ve aktarması son derece kolaydır .


4
Lütfen teklifinizle ilgili yapılandırılmış bir formda bir sözde kod sağlayabilir misiniz? Kulağa ilginç geliyor.
Léo Léopold Hertz 준영

0

Base64 biçimini kullanarak bir GUID'i kodlamanın ve 22 karakterlik bir dize elde etmek için sondaki == kısaltmanın basitliğini gerçekten seviyorum (bir satır kod alır ve her zaman GUID'e dönüştürebilirsiniz). Maalesef bazen + ve / karakterleri içerir. Veritabanı için tamam, URL'ler için harika değil, ancak diğer yanıtları takdir etmeme yardımcı oldu :-)

Gönderen https://www.codeproject.com/Tips/1236704/Reducing-the-string-Length-of-a-Guid Christiaan van Bergen tarafından

Guid'i (16 bayt) Base64 kullanarak bir ASCII gösterimine dönüştürmenin, yalnızca 22 karakterlik kullanılabilir ve hala benzersiz bir messageID ile sonuçlandığını bulduk.

var newGuid = Guid.NewGuid();
var messageID = Convert.ToBase64String(newGuid.ToByteArray());

var message22chars = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Substring(0,22);

Örneğin: Guid 'e6248889-2a12-405a-b06d-9695b82c0a9c' (dize uzunluğu: 36) bir Base64 gösterimi alacaktır: 'iYgk5hIqWkCwbZaVuCwKnA ==' (dize uzunluğu: 24)

Base64 gösterimi '==' karakterleriyle biter. Benzersizliği herhangi bir şekilde etkilemeden bunları kesebilirsiniz. Size sadece 22 karakter uzunluğunda bir tanımlayıcı bırakıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.