web-dev-qa-db-fra.com

Générateur de chaîne aléatoire renvoyant la même chaîne

J'ai développé un générateur de chaîne aléatoire, mais il ne se comporte pas exactement comme je l'espère. Mon objectif est de pouvoir exécuter ceci deux fois et générer deux chaînes aléatoires distinctes de quatre caractères. Cependant, il génère simplement une chaîne aléatoire de quatre caractères deux fois.

Voici le code et un exemple de sa sortie:

private string RandomString(int size)
{
    StringBuilder builder = new StringBuilder();
    Random random = new Random();
    char ch;
    for (int i = 0; i < size; i++)
    {
        ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));                 
        builder.Append(ch);
    }

    return builder.ToString();
}

// get 1st random string 
string Rand1 = RandomString(4);

// get 2nd random string 
string Rand2 = RandomString(4);

// create full Rand string
string docNum = Rand1 + "-" + Rand2;

... et le résultat ressemble à ceci: UNTE-UNTE ... mais devrait ressembler à ceci: UNTE-FWNU

Comment puis-je assurer deux chaînes distinctement aléatoires?

222
PushCode

Vous créez l'occurrence aléatoire dans la méthode, ce qui lui permet de renvoyer les mêmes valeurs lorsqu'il est appelé successivement. Je ferais quelque chose comme ça:

private static Random random = new Random((int)DateTime.Now.Ticks);//thanks to McAden
private string RandomString(int size)
    {
        StringBuilder builder = new StringBuilder();
        char ch;
        for (int i = 0; i < size; i++)
        {
            ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));                 
            builder.Append(ch);
        }

        return builder.ToString();
    }

// get 1st random string 
string Rand1 = RandomString(4);

// get 2nd random string 
string Rand2 = RandomString(4);

// creat full Rand string
string docNum = Rand1 + "-" + Rand2;

(version modifiée de votre code)

304
RCIX

Vous instanciez l'objet Random dans votre méthode.

L'objet Random est issu de l'horloge système , ce qui signifie que si vous appelez votre méthode plusieurs fois à la suite, elle utilisera à chaque fois la même valeur d'origine, ce qui signifie générer la même séquence de nombres aléatoires, ce qui signifie que vous obtiendrez la même chaîne.

Pour résoudre le problème, déplacez votre instance Random en dehors de la méthode elle-même (et tant que vous y serez, vous pourrez vous débarrasser de cette folle séquence d'appels à Convert et Floor et NextDouble):

private readonly Random _rng = new Random();
private const string _chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

private string RandomString(int size)
{
    char[] buffer = new char[size];

    for (int i = 0; i < size; i++)
    {
        buffer[i] = _chars[_rng.Next(_chars.Length)];
    }
    return new string(buffer);
}
186
LukeH

// Une implémentation très simple

using System.IO;   
public static string RandomStr()

{
    string rStr = Path.GetRandomFileName();
    rStr = rStr.Replace(".", ""); // For Removing the .
    return rStr;
}

// Maintenant, il suffit d'appeler RandomStr () Method

134
Ranvir

Tant que vous utilisez Asp.Net 2.0 ou une version ultérieure, vous pouvez également utiliser l'appel de la bibliothèque - System.Web.Security.Membership.GeneratePassword , mais il comportera des caractères spéciaux.

Pour obtenir 4 caractères aléatoires avec un minimum de 0 caractères spéciaux-

_Membership.GeneratePassword(4, 0)
_
49
Spongeboy

Juste pour les gens qui s'arrêtent et quoi d'avoir une chaîne aléatoire dans une seule ligne de code

int yourRandomStringLength = 12; //maximum: 32
Guid.NewGuid().ToString("N").Substring(0, yourRandomStringLength);

PS: Veuillez garder à l’esprit que yourRandomStringLength ne peut pas dépasser 32 car Guid a une longueur maximale de 32.

20
Abdul Munim

Cette solution est une extension pour une classe Random .

Usage

class Program
{
    private static Random random = new Random(); 

    static void Main(string[] args)
    {
        random.NextString(10); // "cH*%I\fUWH0"
        random.NextString(10); // "Cw&N%27+EM"
        random.NextString(10); // "0LZ}nEJ}_-"
        random.NextString();   // "kFmeget80LZ}nEJ}_-"
    }
}

La mise en oeuvre

public static class RandomEx
{
    /// <summary>
    /// Generates random string of printable ASCII symbols of a given length
    /// </summary>
    /// <param name="r">instance of the Random class</param>
    /// <param name="length">length of a random string</param>
    /// <returns>Random string of a given length</returns>
    public static string NextString(this Random r, int length)
    {
        var data = new byte[length];
        for (int i = 0; i < data.Length; i++)
        {
            // All ASCII symbols: printable and non-printable
            // data[i] = (byte)r.Next(0, 128);
            // Only printable ASCII
            data[i] = (byte)r.Next(32, 127);
        }
        var encoding = new ASCIIEncoding();
        return encoding.GetString(data);
    }

    /// <summary>
    /// Generates random string of printable ASCII symbols
    /// with random length of 10 to 20 chars
    /// </summary>
    /// <param name="r">instance of the Random class</param>
    /// <returns>Random string of a random length between 10 and 20 chars</returns>
    public static string NextString(this Random r)
    {
        int length  = r.Next(10, 21);
        return NextString(r, length);
    }
}
13
oleksii

Encore une autre version du générateur de chaînes. Simple, sans mathématiques sophistiquées ni chiffres magiques. Mais avec une chaîne magique qui spécifie les caractères autorisés.

Mise à jour: J'ai créé un générateur statique, afin qu'il ne renvoie pas la même chaîne lorsqu'il est appelé plusieurs fois. Cependant ce code est pas thread-safe et est définitivement non cryptographiquement sécurisé .

Pour la génération de mot de passe System.Security.Cryptography.RNGCryptoServiceProvider doit être utilisé.

_private Random _random = new Random(Environment.TickCount);

public string RandomString(int length)
{
    string chars = "0123456789abcdefghijklmnopqrstuvwxyz";
    StringBuilder builder = new StringBuilder(length);

    for (int i = 0; i < length; ++i)
        builder.Append(chars[_random.Next(chars.Length)]);

    return builder.ToString();
}
_
12
Maksym Davydov

Voici une autre option:

public System.String GetRandomString(System.Int32 length)
{
    System.Byte[] seedBuffer = new System.Byte[4];
    using (var rngCryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider())
    {
        rngCryptoServiceProvider.GetBytes(seedBuffer);
        System.String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        System.Random random = new System.Random(System.BitConverter.ToInt32(seedBuffer, 0));
        return new System.String(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());
    }
}
10
Zygimantas

La meilleure solution consiste à utiliser le générateur de nombres aléatoires avec la conversion base64

public string GenRandString(int length)
{
  byte[] randBuffer = new byte[length];
  RandomNumberGenerator.Create().GetBytes(randBuffer);
  return System.Convert.ToBase64String(randBuffer).Remove(length);
}
7
Ami Luttwak

Un LINQ one-liner pour faire bonne mesure (en supposant un private static Random Random) ...

public static string RandomString(int length)
{
    return new string(Enumerable.Range(0, length).Select(_ => (char)Random.Next('a', 'z')).ToArray());
}
4
AlexFoxGill

Cela est dû au fait que chaque nouvelle instance de Random génère le même nombre d'appels appelés si rapidement. ne pas continuer à créer une nouvelle instance, appelez simplement next () et déclarez votre classe aléatoire en dehors de votre méthode.

4
John T

Vous devez avoir un objet aléatoire de niveau classe initié une fois dans le constructeur et réutilisé à chaque appel (ceci continue la même séquence de nombres pseudo-aléatoires). Le constructeur sans paramètre ensemence déjà le générateur avec Environment.TickCount en interne.

3
Kenan E. K.

J'ai ajouté l'option permettant de choisir la longueur à l'aide de la solution Ranvir

public static string GenerateRandomString(int length)
    {
        {
            string randomString= string.Empty;

            while (randomString.Length <= length)
            {
                randomString+= Path.GetRandomFileName();
                randomString= randomString.Replace(".", string.Empty);
            }

            return randomString.Substring(0, length);
        }
    }
2
João Miguel

Ma méthode RandomString() pour générer une chaîne aléatoire.

private static readonly Random _Rand = new Random();

/// <summary>
/// Generate a random string.
/// </summary>
/// <param name="length">The length of random string. The minimum length is 3.</param>
/// <returns>The random string.</returns>
public string RandomString(int length)
{
    length = Math.Max(length, 3);

    byte[] bytes = new byte[length];
    _Rand.NextBytes(bytes);
    return Convert.ToBase64String(bytes).Substring(0, length);
}
2
AechoLiu

Je pense que c'est peut-être aussi acceptable et simple.

Guid.NewGuid().ToString() 
2
wener

Voici ma modification de la réponse actuellement acceptée, que je pense être un peu plus rapide et plus courte:

private static Random random = new Random();

private string RandomString(int size) {
    StringBuilder builder = new StringBuilder(size);
    for (int i = 0; i < size; i++)
        builder.Append((char)random.Next(0x41, 0x5A));
    return builder.ToString();
}

Notez que je n’ai pas utilisé toute la multiplication, Math.floor(), Convert etc.

EDIT: random.Next(0x41, 0x5A) peut être modifié pour toute plage de caractères Unicode.

2
quantum
public static class StringHelpers
{
    public static readonly Random rnd = new Random();

    public static readonly string EnglishAlphabet = "abcdefghijklmnopqrstuvwxyz";
    public static readonly string RussianAlphabet = "абвгдеёжзийклмнопрстуфхцчшщъыьэюя";

    public static unsafe string GenerateRandomUTF8String(int length, string alphabet)
    {
        if (length <= 0)
            return String.Empty;
        if (string.IsNullOrWhiteSpace(alphabet))
            throw new ArgumentNullException("alphabet");

        byte[] randomBytes = rnd.NextBytes(length);

        string s = new string(alphabet[0], length);

        fixed (char* p = s)
        {
            for (int i = 0; i < s.Length; i++)
            {
                *(p + i) = alphabet[randomBytes[i] % alphabet.Length];
            }
        }
        return s;
    }

    public static unsafe string GenerateRandomUTF8String(int length, params UnicodeCategory[] unicodeCategories)
    {
        if (length <= 0)
            return String.Empty;
        if (unicodeCategories == null)
            throw new ArgumentNullException("unicodeCategories");
        if (unicodeCategories.Length == 0)
            return rnd.NextString(length);

        byte[] randomBytes = rnd.NextBytes(length);

        string s = randomBytes.ConvertToString();
        fixed (char* p = s)
        {
            for (int i = 0; i < s.Length; i++)
            {
                while (!unicodeCategories.Contains(char.GetUnicodeCategory(*(p + i))))
                    *(p + i) += (char)*(p + i);
            }
        }
        return s;
    }
}

Vous aurez également besoin de ceci:

public static class RandomExtensions
{
    public static string NextString(this Random rnd, int length)
    {
        if (length <= 0)
            return String.Empty;

        return rnd.NextBytes(length).ConvertToString();
    }

    public static byte[] NextBytes(this Random rnd, int length)
    {
        if (length <= 0)
            return new byte[0];

        byte[] randomBytes = new byte[length];
        rnd.NextBytes(randomBytes);
        return randomBytes;
    }
}

Et ça:

public static class ByteArrayExtensions
{
    public static string ConvertToString(this byte[] bytes)
    {
        if (bytes.Length <= 0)
            return string.Empty;

        char[] chars = new char[bytes.Length / sizeof(char)];
        Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
        return new string(chars);
    }
}
1
Konard

Et voici une autre idée basée sur les GUID. Je l'ai utilisé pour le test de performance Visual Studio pour générer une chaîne aléatoire contenant uniquement des caractères alphanumériques.

public string GenerateRandomString(int stringLength)
{
    Random rnd = new Random();
    Guid guid;
    String randomString = string.Empty;

    int numberOfGuidsRequired = (int)Math.Ceiling((double)stringLength / 32d);
    for (int i = 0; i < numberOfGuidsRequired; i++)
    {
        guid = Guid.NewGuid();
        randomString += guid.ToString().Replace("-", "");
    }

    return randomString.Substring(0, stringLength);
}
1
Maciej Zaleski

En fait, une bonne solution consiste à utiliser une méthode statique pour le générateur de nombres aléatoires, qui est thread-safe et qui n’utilise pas de verrous.

De cette façon, plusieurs utilisateurs accédant à votre application Web en même temps ne reçoivent pas les mêmes chaînes aléatoires.

Il y a 3 exemples ici: http://blogs.msdn.com/b/pfxteam/archive/2009/02/19/9434171.aspx

J'utiliserais le dernier:

public static class RandomGen3
{
    private static RNGCryptoServiceProvider _global = 
        new RNGCryptoServiceProvider();
    [ThreadStatic]
    private static Random _local;

    public static int Next()
    {
        Random inst = _local;
        if (inst == null)
        {
            byte[] buffer = new byte[4];
            _global.GetBytes(buffer);
            _local = inst = new Random(
                BitConverter.ToInt32(buffer, 0));
        }
        return inst.Next();
    }
}

Ensuite, vous pouvez éliminer correctement

Random random = new Random();

Et appelez simplement RandomGen3.Next (), alors que votre méthode peut rester statique.

1
Stefan Steiger

Si vous souhaitez générer une chaîne de chiffres et de caractères pour un mot de passe fort.

private static Random random = new Random();

private static string CreateTempPass(int size)
        {
            var pass = new StringBuilder();
            for (var i=0; i < size; i++)
            {
                var binary = random.Next(0,2);
                switch (binary)
                {
                    case 0:
                    var ch = (Convert.ToChar(Convert.ToInt32(Math.Floor(26*random.NextDouble() + 65))));
                        pass.Append(ch);
                        break;
                    case 1:
                        var num = random.Next(1, 10);
                        pass.Append(num);
                        break;
                }
            }
            return pass.ToString();
        }
1
CGsoldier

J'ai créé cette méthode.

Ça marche très bien.

public static string GeneratePassword(int Lenght, int NonAlphaNumericChars)
    {
        string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
        string allowedNonAlphaNum = "!@#$%^&*()_-+=[{]};:<>|./?";
        Random rd = new Random();

        if (NonAlphaNumericChars > Lenght || Lenght <= 0 || NonAlphaNumericChars < 0)
            throw new ArgumentOutOfRangeException();

            char[] pass = new char[Lenght];
            int[] pos = new int[Lenght];
            int i = 0, j = 0, temp = 0;
            bool flag = false;

            //Random the position values of the pos array for the string Pass
            while (i < Lenght - 1)
            {
                j = 0;
                flag = false;
                temp = rd.Next(0, Lenght);
                for (j = 0; j < Lenght; j++)
                    if (temp == pos[j])
                    {
                        flag = true;
                        j = Lenght;
                    }

                if (!flag)
                {
                    pos[i] = temp;
                    i++;
                }
            }

            //Random the AlphaNumericChars
            for (i = 0; i < Lenght - NonAlphaNumericChars; i++)
                pass[i] = allowedChars[rd.Next(0, allowedChars.Length)];

            //Random the NonAlphaNumericChars
            for (i = Lenght - NonAlphaNumericChars; i < Lenght; i++)
                pass[i] = allowedNonAlphaNum[rd.Next(0, allowedNonAlphaNum.Length)];

            //Set the sorted array values by the pos array for the rigth posistion
            char[] sorted = new char[Lenght];
            for (i = 0; i < Lenght; i++)
                sorted[i] = pass[pos[i]];

            string Pass = new String(sorted);

            return Pass;
    }
1
Hugo

Pour le générateur de chaîne aléatoire:

#region CREATE RANDOM STRING Word
        char[] wrandom = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','R','S','T','U','V','X','W','Y','Z'};
        Random random = new Random();
        string random_string = "";
        int count = 12; //YOU WILL SPECIFY HOW MANY CHARACTER WILL BE GENERATE
        for (int i = 0; i < count; i++ )
        {
            random_string = random_string + wrandom[random.Next(0, 24)].ToString(); 
        }
        MessageBox.Show(random_string);
        #endregion
1
Toprak

Combinant la réponse par "Pushcode" et celle utilisant la graine pour le générateur aléatoire. J'en avais besoin pour créer une série de "mots" pseudo-lisibles.

private int RandomNumber(int min, int max, int seed=0)
{
    Random random = new Random((int)DateTime.Now.Ticks + seed);
    return random.Next(min, max);
}
1
Ideogram

Voici un article de blog qui fournit une classe un peu plus robuste pour générer des mots, des phrases et des paragraphes aléatoires.

1
Nick Olsen

Dans ma situation, le mot de passe doit contenir:

  • Au moins une minuscule.
  • Au moins une majuscule.
  • Au moins une décimale.
  • Au moins un caractère spécial.

Voici mon code:

    private string CreatePassword(int len)
    {
        string[] valid = { "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "1234567890", "!@#$%^&*()_+" };
        RNGCryptoServiceProvider rndGen = new RNGCryptoServiceProvider();

        byte[] random = new byte[len];
        int[] selected = new int[len];

        do
        {
            rndGen.GetNonZeroBytes(random);

            for (int i = 0; i < random.Length; i++)
            {
                selected[i] = random[i] % 4;
            }
        } 
        while(selected.Distinct().Count() != 4);

        rndGen.GetNonZeroBytes(random);

        string res = "";

        for(int i = 0; i<len; i++)
        {
            res += valid[selected[i]][random[i] % valid[selected[i]].Length];
        }
        return res;
    }
0
Jules

Si vous avez accès à un processeur compatible Intel Secure Key, vous pouvez générer des nombres et des chaînes aléatoires réels à l'aide de ces bibliothèques: https://github.com/JebteK/RdRand et https://www.rdrand.com/

Il suffit de télécharger la dernière version de ici , d'inclure Jebtek.RdRand et d'ajouter une instruction using pour elle. Ensuite, tout ce que vous devez faire est la suivante:

bool isAvailable = RdRandom.GeneratorAvailable(); //Check to see if this is a compatible CPU
string key = RdRandom.GenerateKey(10); //Generate 10 random characters

De plus, vous bénéficiez également de ces fonctionnalités supplémentaires:

string apiKey = RdRandom.GenerateAPIKey(); //Generate 64 random characters, useful for API keys
byte[] b = RdRandom.GenerateBytes(10); //Generate an array of 10 random bytes
uint i = RdRandom.GenerateUnsignedInt() //Generate a random unsigned int

Si vous n'avez pas de CPU compatible pour exécuter le code, utilisez simplement les services RESTful sur rdrand.com. Avec la bibliothèque de wrapper RdRandom incluse dans votre projet, il vous suffira de le faire (vous recevez 1000 appels gratuits lors de votre inscription):

string ret = Randomizer.GenerateKey(<length>, "<key>");

Vous pouvez également générer des tableaux d’octets aléatoires et des entiers non signés comme suit:

uint ret = Randomizer.GenerateUInt("<key>");
byte[] ret = Randomizer.GenerateBytes(<length>, "<key>");
0
JebaDaHut

Salut
vous pouvez utiliser WordGenerator ou LoremIpsumGenerator à partir du package de nuget MMLib.RapidPrototyping.

using MMLib.RapidPrototyping.Generators;
public void WordGeneratorExample()
{
   WordGenerator generator = new WordGenerator();
   var randomWord = generator.Next();

   Console.WriteLine(randomWord);
} 

site Nuget
site du projet Codeplex

0
Mino

J'ai trouvé cela plus utile, puisqu'il s'agit d'une extension et qu'il vous permet de sélectionner la source de votre code.

static string
    numbers = "0123456789",
    letters = "abcdefghijklmnopqrstvwxyz",
    lettersUp = letters.ToUpper(),
    codeAll = numbers + letters + lettersUp;

static Random m_Rand = new Random();

public static string GenerateCode(this int size)
{
    return size.GenerateCode(CodeGeneratorType.All);
}

public static string GenerateCode(this int size, CodeGeneratorType type)
{
    string source;

    if (type == CodeGeneratorType.All)
    {
        source = codeAll;
    }
    else
    {
        StringBuilder sourceBuilder = new StringBuilder();
        if ((type & CodeGeneratorType.Letters) == CodeGeneratorType.Numbers)
            sourceBuilder.Append(numbers);
        if ((type & CodeGeneratorType.Letters) == CodeGeneratorType.Letters)
            sourceBuilder.Append(letters);
        if ((type & CodeGeneratorType.Letters) == CodeGeneratorType.LettersUpperCase)
            sourceBuilder.Append(lettersUp);

        source = sourceBuilder.ToString();
    }

    return size.GenerateCode(source);
}

public static string GenerateCode(this int size, string source)
{
    StringBuilder code = new StringBuilder();
    int maxIndex = source.Length-1;
    for (int i = 0; i < size; i++)
    {

        code.Append(source[Convert.ToInt32(Math.Round(m_Rand.NextDouble() * maxIndex))]);
    }

    return code.ToString();
}

public enum CodeGeneratorType { Numbers = 1, Letters = 2, LettersUpperCase = 4, All = 16 };

J'espère que cela t'aides.

0
WhyMe

n autre échantillon (testé en vs2013):

    Random R = new Random();
    public static string GetRandomString(int Length)
    {
        char[] ArrRandomChar = new char[Length];
        for (int i = 0; i < Length; i++)
            ArrRandomChar[i] = (char)('a' + R.Next(0, 26));
        return new string(ArrRandomChar);
    }

    string D = GetRandomString(12);

Mis en œuvre par moi-même.

0
Amin Ghaderi

Et une autre version: j’utilise cette méthode pour générer des pseudo-symboles aléatoires dans des tests:

Random Rand = new Random();
Func<char> randChar = () => (char)Rand.Next(65, 91); // upper case ascii codes
Func<int,string> randStr = null;
    randStr = (x) => (x>0) ? randStr(--x)+randChar() : ""; // recursive

Usage:

string str4 = randStr(4);// generates a random 4 char string
string strx = randStr(Rand.next(1,5)); // random string between 1-4 chars in length

Vous pouvez redéfinir la fonction randChar à utiliser avec un tableau de caractères "autorisé" par position au lieu de code ascii:

char[] allowedchars = {'A','B','C','1','2','3'};
Func<char> randChar = () => allowedchars[Rand.Next(0, allowedchars.Length-1)];
0
cramroop

Ceci est ma solution:

private string RandomString(int length)
{
    char[] symbols = { 
                            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                            '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'                             
                        };

    Stack<byte> bytes = new Stack<byte>();
    string output = string.Empty;

    for (int i = 0; i < length; i++)
    {
        if (bytes.Count == 0)
        {
            bytes = new Stack<byte>(Guid.NewGuid().ToByteArray());
        }
        byte pop = bytes.Pop();
        output += symbols[(int)pop % symbols.Length];
    }
    return output;
}

// get 1st random string 
string Rand1 = RandomString(4);

// get 2nd random string 
string Rand2 = RandomString(4);

// create full Rand string
string docNum = Rand1 + "-" + Rand2;
0
ADM-IT