Question Comment puis-je générer des chaînes alphanumériques aléatoires en C #? [fermé]


Comment puis-je générer des chaînes alphanumériques aléatoires à 8 caractères en C #?


708
2017-08-27 23:07


origine


Réponses:


J'ai entendu LINQ est le nouveau noir, alors voici ma tentative en utilisant LINQ:

private static Random random = new Random();
public static string RandomString(int length)
{
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    return new string(Enumerable.Repeat(chars, length)
      .Select(s => s[random.Next(s.Length)]).ToArray());
}

(Remarque: L'utilisation de la classe Random la rend inapte à tout ce qui est lié à la sécurité, comme la création de mots de passe ou de jetons.
Utilisez la classe RNGCryptoServiceProvider si vous avez besoin d'un générateur de nombres aléatoires fort.)


1311
2017-08-27 23:13



var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var stringChars = new char[8];
var random = new Random();

for (int i = 0; i < stringChars.Length; i++)
{
    stringChars[i] = chars[random.Next(chars.Length)];
}

var finalString = new String(stringChars);

Pas aussi élégant que la solution Linq. (-:

(Note: L'utilisation de la classe Random rend cette impropre à tout ce qui concerne la sécurité, comme la création de mots de passe ou de jetons. Utilisez la classe RNGCryptoServiceProvider si vous avez besoin d'un générateur de nombres aléatoires fort.)


276
2017-08-27 23:21



Cette implémentation (trouvée via google) me semble bien.

Contrairement à certaines des alternatives présentées, celle-ci est son cryptographiquement.

using System.Security.Cryptography;
using System.Text;

namespace UniqueKey
{
    public class KeyGenerator
    {
        public static string GetUniqueKey(int maxSize)
        {
            char[] chars = new char[62];
            chars =
            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
            byte[] data = new byte[1];
            using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
            {
                crypto.GetNonZeroBytes(data);
                data = new byte[maxSize];
                crypto.GetNonZeroBytes(data);
            }
            StringBuilder result = new StringBuilder(maxSize);
            foreach (byte b in data)
            {
                result.Append(chars[b % (chars.Length)]);
            }
            return result.ToString();
        }
    }
}

Choisi celui d'une discussion sur les alternatives ici


247
2017-08-27 23:19



Solution 1 - la plus grande «gamme» avec la longueur la plus flexible

string get_unique_string(int string_length) {
    using(var rng = new RNGCryptoServiceProvider()) {
        var bit_count = (string_length * 6);
        var byte_count = ((bit_count + 7) / 8); // rounded up
        var bytes = new byte[byte_count];
        rng.GetBytes(bytes);
        return Convert.ToBase64String(bytes);
    }
}

Cette solution a plus de portée que l'utilisation d'un GUID car un GUID a un couple de bits fixes qui sont toujours les mêmes et donc pas aléatoires, par exemple le 13 caractères hexadécimal est toujours "4" - au moins dans un GUID version 6.

Cette solution vous permet également de générer une chaîne de n'importe quelle longueur.

Solution 2 - Une ligne de code - valable jusqu'à 22 caractères

Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Substring(0, 8);

Vous ne pouvez pas générer de chaînes tant que Solution 1 et la chaîne n'a pas la même plage en raison de bits fixes dans les GUID, mais dans de nombreux cas, cela fera l'affaire.

Solution 3 - Un peu moins de code

Guid.NewGuid().ToString("n").Substring(0, 8);

Principalement en gardant ceci ici à des fins historiques. Il utilise un peu moins de code, ce qui revient à dépenser moins d'espace - car il utilise hex au lieu de base64, il faut plus de caractères pour représenter la même plage par rapport aux autres solutions.

Ce qui signifie plus de chance de collision - le tester avec 100 000 itérations de 8 chaînes de caractères a généré un doublon.


160
2017-08-28 00:00



Voici un exemple que j'ai volé à Sam Allen exemple à Dot Perls Net

Si vous n'avez besoin que de 8 caractères, utilisez Path.GetRandomFileName () dans l'espace de noms System.IO. Sam dit que l'utilisation de la méthode "Path.GetRandomFileName" est parfois supérieure, car elle utilise RNGCryptoServiceProvider pour un meilleur caractère aléatoire, mais elle est limitée à 11 caractères aléatoires. "

GetRandomFileName renvoie toujours une chaîne de 12 caractères avec un point au 9ème caractère. Donc, vous aurez besoin de dépouiller la période (puisque ce n'est pas aléatoire) et ensuite prendre 8 caractères de la chaîne. En fait, vous pouvez simplement prendre les 8 premiers caractères et ne pas s'inquiéter de la période.

public string Get8CharacterRandomString()
{
    string path = Path.GetRandomFileName();
    path = path.Replace(".", ""); // Remove period.
    return path.Substring(0, 8);  // Return 8 character string
}

PS: merci Sam


52
2017-08-27 23:36



Les principaux objectifs de mon code sont:

  1. La distribution des cordes est presque uniforme (ne pas se soucier des écarts mineurs, tant qu'ils sont petits)
  2. Il génère plus de quelques milliards de chaînes pour chaque jeu d'arguments. Générer une chaîne de 8 caractères (~ 47 bits d'entropie) n'a pas de sens si votre PRNG ne génère que 2 milliards (31 bits d'entropie) de valeurs différentes.
  3. C'est sécurisé, puisque je m'attends à ce que les gens l'utilisent pour les mots de passe ou autres jetons de sécurité.

La première propriété est obtenue en prenant une valeur de 64 bits modulo la taille de l'alphabet. Pour les petits alphabets (tels que les 62 caractères de la question), cela conduit à un biais négligeable. La deuxième et la troisième propriété sont obtenues en utilisant RNGCryptoServiceProvider au lieu de System.Random.

using System;
using System.Security.Cryptography;

public static string GetRandomAlphanumericString(int length)
{
    const string alphanumericCharacters =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
        "abcdefghijklmnopqrstuvwxyz" +
        "0123456789";
    return GetRandomString(length, alphanumericCharacters);
}

public static string GetRandomString(int length, IEnumerable<char> characterSet)
{
    if (length < 0)
        throw new ArgumentException("length must not be negative", "length");
    if (length > int.MaxValue / 8) // 250 million chars ought to be enough for anybody
        throw new ArgumentException("length is too big", "length");
    if (characterSet == null)
        throw new ArgumentNullException("characterSet");
    var characterArray = characterSet.Distinct().ToArray();
    if (characterArray.Length == 0)
        throw new ArgumentException("characterSet must not be empty", "characterSet");

    var bytes = new byte[length * 8];
    new RNGCryptoServiceProvider().GetBytes(bytes);
    var result = new char[length];
    for (int i = 0; i < length; i++)
    {
        ulong value = BitConverter.ToUInt64(bytes, i * 8);
        result[i] = characterArray[value % (uint)characterArray.Length];
    }
    return new string(result);
}

31
2017-11-16 11:57



Le plus simple:

public static string GetRandomAlphaNumeric()
{
    return Path.GetRandomFileName().Replace(".", "").Substring(0, 8);
}

Vous pouvez obtenir de meilleures performances si vous codez durablement le tableau de char et comptez sur System.Random:

public static string GetRandomAlphaNumeric()
{
    var chars = "abcdefghijklmnopqrstuvwxyz0123456789";
    return new string(chars.Select(c => chars[random.Next(chars.Length)]).Take(8).ToArray());
}

Si jamais vous vous inquiétez les alphabets anglais peuvent changer quelque part autour et vous pourriez perdre des affaires, alors vous pouvez éviter le codage dur, mais devrait fonctionner légèrement plus mauvais (comparable à Path.GetRandomFileName approche)

public static string GetRandomAlphaNumeric()
{
    var chars = 'a'.To('z').Concat('0'.To('9')).ToList();
    return new string(chars.Select(c => chars[random.Next(chars.Length)]).Take(8).ToArray());
}

public static IEnumerable<char> To(this char start, char end)
{
    if (end < start)
        throw new ArgumentOutOfRangeException("the end char should not be less than start char", innerException: null);
    return Enumerable.Range(start, end - start + 1).Select(i => (char)i);
}

Les deux dernières approches semblent meilleures si vous pouvez en faire une méthode d'extension System.Random exemple.


28
2018-04-13 07:09



Juste quelques comparaisons de performance des différentes réponses dans ce fil:

Méthodes et configuration

// what's available
public static string possibleChars = "abcdefghijklmnopqrstuvwxyz";
// optimized (?) what's available
public static char[] possibleCharsArray = possibleChars.ToCharArray();
// optimized (precalculated) count
public static int possibleCharsAvailable = possibleChars.Length;
// shared randomization thingy
public static Random random = new Random();


// http://stackoverflow.com/a/1344242/1037948
public string LinqIsTheNewBlack(int num) {
    return new string(
    Enumerable.Repeat(possibleCharsArray, num)
              .Select(s => s[random.Next(s.Length)])
              .ToArray());
}

// http://stackoverflow.com/a/1344258/1037948
public string ForLoop(int num) {
    var result = new char[num];
    while(num-- > 0) {
        result[num] = possibleCharsArray[random.Next(possibleCharsAvailable)];
    }
    return new string(result);
}

public string ForLoopNonOptimized(int num) {
    var result = new char[num];
    while(num-- > 0) {
        result[num] = possibleChars[random.Next(possibleChars.Length)];
    }
    return new string(result);
}

public string Repeat(int num) {
    return new string(new char[num].Select(o => possibleCharsArray[random.Next(possibleCharsAvailable)]).ToArray());
}

// http://stackoverflow.com/a/1518495/1037948
public string GenerateRandomString(int num) {
  var rBytes = new byte[num];
  random.NextBytes(rBytes);
  var rName = new char[num];
  while(num-- > 0)
    rName[num] = possibleCharsArray[rBytes[num] % possibleCharsAvailable];
  return new string(rName);
}

//SecureFastRandom - or SolidSwiftRandom
static string GenerateRandomString(int Length) //Configurable output string length
{
    byte[] rBytes = new byte[Length]; 
    char[] rName = new char[Length];
    SolidSwiftRandom.GetNextBytesWithMax(rBytes, biasZone);
    for (var i = 0; i < Length; i++)
    {
        rName[i] = charSet[rBytes[i] % charSet.Length];
    }
    return new string(rName);
}

Résultats

Testé dans LinqPad. Pour une taille de chaîne de 10, génère:

  • de Linq = chdgmevhcy [10]
  • à partir de Loop = gtnoaryhxr [10]
  • de Select = rsndbztyby [10]
  • de GenerateRandomString = owyefjjakj [10]
  • de SecureFastRandom = VzougLYHYP [10]
  • de SecureFastRandom-NoCache = oVQXNGmO1S [10]

Et les chiffres de performance ont tendance à varier légèrement, très occasionnellement NonOptimized est en fait plus rapide, et parfois ForLoop et GenerateRandomString passer qui est en tête.

  • LinqIsTheNewBlack (10000x) = 96762 ticks écoulés (9.6762 ms)
  • ForLoop (10000x) = 28970 tiques écoulées (2.897 ms)
  • ForLoopNonOptimized (10000x) = 33336 ticks écoulés (3.3336 ms)
  • Répéter (10000x) = 78547 ticks écoulés (7.8547 ms)
  • GenerateRandomString (10000x) = 27416 ticks écoulés (2.7416 ms)
  • SecureFastRandom (10000x) = 13176 ticks écoulés (5ms) le plus bas [Machine différente]
  • SecureFastRandom-NoCache (10000x) = 39541 ticks écoulés (17ms) le plus bas [Machine différente]

17
2018-06-13 16:45



Une ligne de code Membership.GeneratePassword() fait le tour :)

Voici une démo pour le même.


16
2017-07-10 20:40



Le code écrit par Eric J. est assez flou (il est clair qu'il date d'il y a 6 ans ... il n'écrirait probablement pas ce code aujourd'hui), et il y a même quelques problèmes.

Contrairement à certaines des alternatives présentées, celle-ci est cryptographiquement saine.

Untrue ... Il y a un biais dans le mot de passe (comme écrit dans un commentaire), bcdefgh sont un peu plus probables que les autres (le a n'est pas parce que par le GetNonZeroBytes il ne génère pas d'octets avec une valeur de zéro, de sorte que le biais pour la a est équilibré par ça), donc ce n'est pas vraiment cryptographiquement sonore.

Cela devrait corriger tous les problèmes.

public static string GetUniqueKey(int size = 6, string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
{
    using (var crypto = new RNGCryptoServiceProvider())
    {
        var data = new byte[size];

        // If chars.Length isn't a power of 2 then there is a bias if
        // we simply use the modulus operator. The first characters of
        // chars will be more probable than the last ones.

        // buffer used if we encounter an unusable random byte. We will
        // regenerate it in this buffer
        byte[] smallBuffer = null;

        // Maximum random number that can be used without introducing a
        // bias
        int maxRandom = byte.MaxValue - ((byte.MaxValue + 1) % chars.Length);

        crypto.GetBytes(data);

        var result = new char[size];

        for (int i = 0; i < size; i++)
        {
            byte v = data[i];

            while (v > maxRandom)
            {
                if (smallBuffer == null)
                {
                    smallBuffer = new byte[1];
                }

                crypto.GetBytes(smallBuffer);
                v = smallBuffer[0];
            }

            result[i] = chars[v % chars.Length];
        }

        return new string(result);
    }
}

7
2017-08-12 07:53