Quelles sont les options pour générer des identifiants alphanumériques conviviaux (tels que l'ID d'entreprise, SKU)

StackOverflow https://stackoverflow.com/questions/217253

  •  03-07-2019
  •  | 
  •  

Question

Voici les exigences:

Doit être alphanumérique, 8-10 caractères pour que ce soit facile à utiliser. Celles-ci seront stockées en tant que clés uniques dans la base de données. J'utilise des guids en tant que clés primaires. Il serait donc préférable d'utiliser les guids pour générer ces identifiants uniques.

Je pense aux lignes d'un convertisseur base-n qui prend un Guid et se transforme en une chaîne unique de 8 caractères.

Un algorithme court et léger a été préféré car il serait appelé assez souvent.

Était-ce utile?

La solution

Vous pourriez envisager de base 36. , dans la mesure où il sait faire des lettres et des chiffres. Envisagez de retirer les éléments I (œil) et O (Oh) de votre ensemble afin qu'ils ne soient pas mélangés avec 1 (un) et 0 (zéro). Certaines personnes pourraient également se plaindre de 2 et de Z.

Autres conseils

8 characters - perfectly random - 36^8 = 2,821,109,907,456 combinations
10 characters - perfectly random - 36^10 = 3,656,158,440,062,976 combinations
GUID's - statistically unique* - 2^128 = 340,000,000,000,000,000,000,000,000,000,000,000,000 combinations

* Un GUID est-il unique dans 100% des cas? [stackoverflow]

Le problème avec votre GUID - > conversion de caractère; tandis que votre GUID est statistiquement unique, en prenant n'importe quel sous-ensemble, vous diminuez le caractère aléatoire et augmentez les risques de collision. Vous ne voulez certainement pas créer de SKU non-uniformes.

Solution 1:

Créez une SKU en utilisant des données pertinentes pour l'objet et les règles de gestion.

i.e. Il existe probablement une petite combinaison d'attributs qui rendent un objet unique (une clé naturelle) . Combinez les éléments de la clé naturelle, codez-les et compressez-les pour créer une SKU. Souvent, tout ce dont vous avez besoin est un champ date-heure (c.-à-d. CreationDate) et quelques autres propriétés pour y parvenir. Vous êtes susceptible d'avoir beaucoup de trous dans la création de sku, mais les sku sont plus pertinents pour vos utilisateurs.

hypothétiquement:

Wholesaler, product name, product version, sku
Amazon,     IPod Nano,    2.2,             AMIPDNN22
BestBuy,    Vaio,         3.2,             BEVAIO32

Solution 2:

Méthode qui réserve une plage de nombres, puis les publie de manière séquentielle et ne renvoie jamais le même nombre deux fois. Vous pouvez toujours vous retrouver avec des trous dans la plage. Il est probable que vous n’ayez pas besoin de générer suffisamment de sku, mais assurez-vous que vos exigences le permettent.

Une implémentation consiste à avoir une table key dans une base de données comportant un compteur. Le compteur est incrémenté dans une transaction. Un point important est que plutôt que d’incrémenter de 1, la méthode logicielle saisit un bloc. Le pseudo-c # -code est le suivant.

-- what the key table may look like
CREATE TABLE Keys(Name VARCHAR(10) primary key, NextID INT)
INSERT INTO Keys Values('sku',1)

// some elements of the class
public static SkuKeyGenerator 
{
    private static syncObject = new object();
    private static int nextID = 0;
    private static int maxID = 0;
    private const int amountToReserve = 100;

    public static int NextKey()
    {
        lock( syncObject )
        {
            if( nextID == maxID )
            {
                ReserveIds();
            }
            return nextID++;
        }
    }
    private static void ReserveIds()
    {
        // pseudocode - in reality I'd do this with a stored procedure inside a transaction,
        // We reserve some predefined number of keys from Keys where Name = 'sku'
        // need to run the select and update in the same transaction because this isn't the only
        // method that can use this table.
        using( Transaction trans = new Transaction() ) // pseudocode.
        {
             int currentTableValue = db.Execute(trans, "SELECT NextID FROM Keys WHERE Name = 'sku'");
             int newMaxID = currentTableValue + amountToReserve;
             db.Execute(trans, "UPDATE Keys SET NextID = @1 WHERE Name = 'sku'", newMaxID);

             trans.Commit();

             nextID = currentTableValue;
             maxID = newMaxID;
        }
    } 

L’idée ici est que vous réserviez suffisamment de clés pour que votre code ne soit pas utilisé fréquemment dans la base de données, car obtenir la gamme de clés est une opération coûteuse. Vous devez avoir une bonne idée du nombre de clés à réserver pour équilibrer la perte de clés (redémarrage de l'application) par rapport à l'épuisement trop rapide des clés et le retour à la base de données. Cette implémentation simple ne permet pas de réutiliser les clés perdues.

Etant donné que cette implémentation repose sur une base de données et sur des transactions, les applications peuvent s'exécuter simultanément et toutes génèrent des clés uniques sans avoir à consulter fréquemment la base de données.

Notez que ce qui précède est vaguement basé sur la table de clés , page 222 de Patterns. d’architecture d’applications d’entreprise (Fowler) . Cette méthode est généralement utilisée pour générer des clés primaires sans avoir besoin d’une colonne d’identité de base de données, mais vous pouvez voir comment elle peut être adaptée à vos besoins.

Si vous recherchez "convivial" " vous voudrez peut-être essayer d'utiliser des mots entiers plutôt que de simplement le rendre court / alphanumérique, par exemple, quelque chose comme:

words = [s.strip().lower() for s in open('/usr/share/dict/canadian-english') if "'" not in s]
mod = len(words)

def main(script, guid):
    guid = hash(guid)

    print "+".join(words[(guid ** e) % mod] for e in (53, 61, 71))

if __name__ == "__main__":
    import sys
    main(*sys.argv)

Qui produit une sortie comme:

oranjestad+compressing+wellspring
padlock+discommoded+blazons
pt+olenek+renews

Ce qui est amusant. Sinon, il est probablement préférable de prendre les 8 à 10 premiers caractères du GUID ou le hachage sha1 / md5 du GUID.

La chose la plus simple qui puisse fonctionner est un compteur incrémenté chaque fois qu’une valeur est requise. Huit chiffres (remplis de zéros à gauche) vous donnent 100 millions de valeurs possibles de 00000000 à 99999999 (bien que vous puissiez interjecter des espaces ou des traits d'union pour la lisibilité humaine, comme dans 000-000-00).

Si vous avez besoin de plus de 100 millions de valeurs, vous pouvez augmenter la longueur ou utiliser des lettres à des positions différentes. L'utilisation de A0A0A0A0 à Z9Z9Z9Z9 vous donne plus de quatre milliards et demi de valeurs possibles (4 569 760 000) disponibles. C'est un bit de code trivial de prendre un entier long et de produire un tel encodage (mod 10 pour le chiffre le plus à droite, div par 10 puis mod 26 pour la lettre la plus à droite, etc.) Si vous avez la mémoire à graver, le moyen le plus rapide consiste à convertir le compteur en tableau de mod 260 et à utiliser chaque valeur de mod 260 comme index en un tableau de chaînes de deux caractères ("A0", "A1", "A2", etc., et ainsi de suite. " A9 "," B0 "," B1 ", etc. à" Z9 ").

Le problème avec la base 36 (mentionnée dans une autre réponse) est que vous devez non seulement vous inquiéter de la confusion des lecteurs de caractères similaires (un contre I, zéro contre O, deux contre Z, cinq contre S), mais ainsi que sur les combinaisons de lettres adjacentes qui pourraient être perçues par les lecteurs comme des orthographes ou des abréviations odieuses ou obscènes.

Vous pouvez essayer un algorithme de hachage CRC32. Le CRC32 génère une chaîne de 8 caractères.

http://en.wikipedia.org/wiki/Cyclic_redundancy_check

http://textop.us/Hashing/CRC

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top