6
votes

Comment créer une séquence aléatoire unique de caractères dans C #?

Je suis implémentant une fonctionnalité de raccourcissement de l'URL dans ma demande afin de fournir à mes utilisateurs des URL d'alternatives plus courtes pouvant être utilisées dans Twitter. Le but doit être indépendant des services de raccourcissement offrant ce même service et l'inclure comme une fonctionnalité de mon application Web.

Quelle est la meilleure façon de créer une séquence aléatoire unique de caractères d'environ 6 caractères? Je prévois d'utiliser cela comme index pour les éléments de ma base de données qui auront les URL alternatives.

édité:

Cette fonctionnalité sera utilisée dans un site Web de la Commission d'emploi, où chaque nouvelle annonce d'emploi obtiendra une URL personnalisée avec le titre plus le plus court à utiliser dans Twitter. Cela dit, le nombre total de 6 combinaisons de charcuterie unique sera plus que suffisant pendant une longue période.


0 commentaires

10 Réponses :


3
votes

Le moyen le plus simple de faire des séquences uniques est de le faire séquentiellement, c'est-à-dire: AAAAAA AAAAAAB AAAAAC ... Ce ne sont pas nécessairement les plus beaux, mais garantissent unicité pour les premières séquences 12230590463 (à condition que vous utilisiez AZ et AZ comme unique. personnages). Si vous avez besoin de plus d'URL que cela, vous auriez besoin d'ajouter un septième caractère.

Ils ne sont pas des séquences aléatoires, cependant. Si vous faites des celles aléatoires, choisissez simplement un caractère aléatoire du 48, 6 fois. Vous devrez vérifier votre DB existant pour les séquences «utilisées», car vous aurez plus de chances d'obtenir des collisions.


3 commentaires

Cela cause plus de travail et des délais d'attente possibles les plus valeurs que vous finissez par utiliser.


Oui. Séquentiel évite tout cela, mais vous vous retrouvez avec des valeurs séquentielles (qui peuvent ou non bien). Pour une URL Twitter, j'utiliserais simplement SEQ. Les valeurs, car cela n'a pas d'importance à quel point ils sont vraiment "aléatoires", et vous auriez une énorme séquence de valeurs uniques, avec une génération simple morte


Si vous incluez 0-9 dans le cadre du jeu de caractères, vous disposez de valeurs uniques 56800235584 (~ 4,6x Just A-Z, A-Z). Je sais qu'il vient de mentionner des "personnages", mais cela pourrait inclure des chiffres. Si vous incluez également d'autres caractères, tels que * $% (), etc., qui augmenteraient également un peu plus (au moins ~ 9x l'ensemble d'origine).



0
votes

En pensant à cela plus ici est une idée.

Vous pouvez commencer par une table à clé, incrémentation des caractères AAAAAA - ZZZZZZZ. P>

puis effectuez une sélection aléatoire de cette table chaque fois que vous insérez une nouvelle URL et supprimez des clés disponibles. P >

pensées? p>

pour Sélectionner aléatoire Essayez ceci LINK P>

Select a random row with MySQL:

SELECT column FROM table
ORDER BY RAND()
LIMIT 1
Select a random row with PostgreSQL:

SELECT column FROM table
ORDER BY RANDOM()
LIMIT 1
Select a random row with Microsoft SQL Server:

SELECT TOP 1 column FROM table
ORDER BY NEWID()
Select a random row with IBM DB2

SELECT column, RAND() as IDX 
FROM table 
ORDER BY IDX FETCH FIRST 1 ROWS ONLY
Thanks Tim

Select a random record with Oracle:

SELECT column FROM
( SELECT column FROM table
ORDER BY dbms_random.value )
WHERE rownum = 1


0 commentaires

2
votes

J'utiliserais un système Autonumber et créeriez un algorithme pour générer les clés. Ie 1 = A, 2 = B, 27 = AA, etc.

Vous pouvez utiliser la base de données Autonomumber pour garantir que votre URL est unique et vous pouvez calculer l'URL éventuellement dans une SPTP dans la DB ou dans votre couche d'entreprise?

En outre, vous pouvez maintenant vous indexer sur le numéro d'incrémentation qui est bon marché et DB est optimisé pour ceux-ci pour être utilisés et haché comme des touches primaires / étrangères, par opposition à une chaîne aléatoire de longueur variable.


0 commentaires

1
votes

L'utilité d'un générateur aléatoire est limitée à empêcher les utilisateurs de brancher des URL aléatoires pour trouver des choses qu'ils ne devraient pas avoir de lien vers. Si ce n'est pas votre objectif, les identifiants séquentiels doivent bien fonctionner. Si vous ne voulez tout simplement pas donner aux utilisateurs l'impression qu'elles utilisent la technologie «nourrisson» (lorsqu'ils voient que leur offre d'emploi est # 000001), pourquoi ne pas démarrer la séquence à une valeur arbitraire?


0 commentaires


0
votes

Au lieu de garder une table de toutes les valeurs possibles, gardez simplement une table des valeurs que vous avez utilisées. Utilisez la fonction aléatoire pour générer 6 valeurs aléatoires, 1 à 26, rendre la chaîne de celle-ci et l'enregistrer dans un tableau ou une table. Si cela existe déjà, vous pouvez (a) générer une autre chaîne, ou (B) se déplacer dans la table sur la chaîne de 6 lettres suivante (manquante) à 6 lettres et utiliser cette valeur. (b) sera plus efficace que la table remplit.


0 commentaires

3
votes

Avez-vous vraiment besoin de "aléatoire" ou serait-il suffisant?

unique est extrêmement simple - insérez simplement l'URL dans une base de données et convertissez l'ID séquentiel pour cet enregistrement à un numéro de base-n qui est représenté par votre personnage de votre choix. P>

Par exemple, si vous Voulez-vous utiliser uniquement [AZ] dans votre séquence, vous convertissez l'ID de l'enregistrement en un numéro de base 26, où A = 1, B = 2, ... Z = 26. L'algothithme est un DIV26 / MOD26 récursif, où le quotient est le caractère requis et le reste est utilisé pour calculer le caractère suivant. P>

puis lors de la récupération de l'URL, vous effectuez la fonction inverse, qui doit convertir le Base-26 Numéro de retour à la décimale. Effectuer une URL de sélection où ID = décimale, et vous avez terminé! P>

EDIT: P>

private string alphabet = "abcdefghijklmnopqrstuvwxyz"; 
   // or whatever you want.  Include more characters 
   // for more combinations and shorter URLs

public string Encode(int databaseId)
{
    string encodedValue = String.Empty;

    while (databaseId > encodingBase)
    {
        int remainder;
        encodedValue += alphabet[Math.DivRem(databaseId, alphabet.Length, 
            out remainder)-1].ToString();
        databaseId = remainder;
    }
    return encodedValue;
}

public int Decode(string code)
{
    int returnValue;

    for (int thisPosition = 0; thisPosition < code.Length; thisPosition++)
    {
        char thisCharacter = code[thisPosition];

        returnValue += alphabet.IndexOf(thisCharacter) * 
            Math.Pow(alphabet.Length, code.Length - thisPosition - 1);
    }
    return returnValue;
}


2 commentaires

Merci pour votre réponse! J'ai une question: Qu'est-ce que encodingbase ?


@Maxim - difficile à retenir il y a plus d'un an, mais j'imagine que c'est la longueur du mot codant; C'est-à-dire pour un codage de base-26 comme ci-dessus, il serait 26. Cependant, je pense qu'il y a aussi un bogue dans le code! Il devrait vraiment être> 1



0
votes

Après l'idée de la réponse de Reed Copsey, je présente le code suivant:

class IDGetter
{
    private StringID ID = new StringID();
    public string GetCurrentID()
    {
        string retStr = "";
        if (ID.char1 > 51)
            id.char1 = 0;
        if (ID.char2 > 51)
            id.char2 = 0;
        if (ID.char3 > 51)
            id.char3 = 0;
        if (ID.char4 > 51)
            id.char4 = 0;
        if (ID.char5 > 51)
            id.char5 = 0;
        if (ID.char6 > 51)
            throw new Exception("the maximum number of id's has been reached");
        return ToIDChar(ID.char1) + ToIDChar(ID.char2) + ToIDChar(ID.char3) + ToIDChar(ID.char4) + ToIDChar(ID.char5) + ToIDChar(ID.char6)
        id.char1++;
    }
    public void SetCurrentID(StringID id) //for setting the current ID from storage or resetting it or something
    {
        this.ID = id;
    }
    private const string alphabet = "abcdefghijklmopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static string ToIDChar(int number)
    {
        if (number > 51 || number < 0)
        {
            throw new InvalidArgumentException("the number passed in (" + number + ") must be between the range 0-51");
        }
        return alphabet[number];
    }
}
public struct StringID 
{
    public int char1 = 0;
    public int char2 = 0;
    public int char3 = 0;
    public int char4 = 0;
    public int char5 = 0;
    public int char6 = 0;
}


0 commentaires

1
votes

Lorsque vous indiquez " Nombre total de 6 combinaisons de charcuterie unique sera plus que suffisant pour une longue période " pour votre génération aléatoire Avez-vous factorisé le Paradox d'anniversaire dans vos calculs? C'est généralement le fléau de toute tentative de création d'IDS aléatoires dans une plage seulement 1 ordre de grandeur ou moins que la plage attendue qui sera nécessaire.

Pour créer des ID vraiment aléatoires, vous devez créer une boucle qui génère une nouvelle valeur aléatoire, vérifie si cette valeur a déjà été utilisée, puis répète la boucle si nécessaire. Le paradoxe d'anniversaire signifie que vous arrivez rapidement au point où de nombreuses valeurs générées sont déjà utilisées (malgré une seule fraction de la portée totale étant consommée), ce qui provoque le programme de devenir plus lent et plus lent au fil du temps jusqu'à ce qu'il soit en milliers de personnes. des tentatives (et des recherches de base de données) pour générer chaque ID.

Je vous suggérerais d'aller avec l'idée d'encoder des identifiants séquentiels. Pour éviter que le problème des utilisateurs puissent simplement incrémenter / décrémenter la valeur de l'URL à "Explorer", vous pouvez utiliser un changement de bits combinant et une liste de lettres commandée alternée (au lieu de 1 = A, 2 = B User 1 = t, 2 = j, etc.).


0 commentaires

0
votes

J'ai utilisé ceci pour faire quelque chose de très similaire. Je ne devais pas m'inquiéter de la vitesse de celui-ci car il allait être un événement et une table rarement utilisés. Mais il est possible d'augmenter la chaîne si nécessaire.

/// Generates a string and checks for existance
/// <returns>Non-existant string as ID</returns>
public static string GetRandomNumbers(int numChars, string Type)
{
    string result = string.Empty;
    bool isUnique = false;
    while (!isUnique)
    {
        //Build the string
        result = MakeID(numChars);
        //Check if unsued
        isUnique = GetValueExists(result, Type);
    }
    return result;
}
/// Builds the string
 public static string MakeID(int numChars)
{
    string random = string.Empty;
    string[] chars = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z" };
    Random rnd = new Random();
    for (int i = 0; i < numChars; i++)
    {
        random += chars[rnd.Next(0, 35)];
    }
    return random;
}
/// Checks database tables based on type for existance, if exists then retry
/// <returns>true or false</returns>
private static bool GetValueExists(string value, string Type)
{
    bool result = false;
    string sql = "";
    if (Type == "URL")
    {
        sql = string.Format(@"IF EXISTS (SELECT COUNT(1) FROM myTable WHERE uniqueString = '{0}')
         BEGIN
             SELECT 1
         END
          ELSE
          BEGIN
             SELECT 0
         END ", value);
    }
    //query the DB to see if it's in use
    result = //ExecuteSQL
    return result;
}


0 commentaires