Pregunta ¿Cómo puedo generar cadenas alfanuméricas aleatorias en C #? [cerrado]


¿Cómo puedo generar cadenas alfanuméricas aleatorias de 8 caracteres en C #?


708
2017-08-27 23:07


origen


Respuestas:


Escuché que LINQ es el nuevo negro, así que aquí está mi intento de usar 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());
}

(Nota: El uso de la clase Random hace que esto no sea adecuado para nada relacionado con la seguridad, como la creación de contraseñas o tokens.
Utilice la clase RNGCryptoServiceProvider si necesita un generador de números aleatorios fuerte).


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);

No tan elegante como la solución de Linq. (-:

(Nota: el uso de la clase Random hace que esto no apto para nada relacionado con la seguridad, como crear contraseñas o tokens. Utilice la clase RNGCryptoServiceProvider si necesita un generador de números aleatorios fuerte).


276
2017-08-27 23:21



Esta implementación (encontrada a través de google) me parece buena.

A diferencia de algunas de las alternativas presentadas, esta es sonido criptográficamente.

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();
        }
    }
}

Elegido ese de una discusión de alternativas aquí


247
2017-08-27 23:19



Solución 1: el "rango" más grande con la longitud más 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);
    }
}

Esta solución tiene más alcance que el uso de un GUID porque un GUID tiene un par de bits fijos que son siempre los mismos y por lo tanto no aleatorios, por ejemplo, los 13 caracteres en hexadecimal siempre son "4", al menos en un GUID de versión 6.

Esta solución también te permite generar una cadena de cualquier longitud.

Solución 2 - Una línea de código - válida para hasta 22 caracteres

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

No puedes generar cadenas siempre y cuando Solución 1 y la cadena no tiene el mismo rango debido a bits fijos en los GUID, pero en muchos casos esto hará el trabajo.

Solución 3: poco menos código

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

Sobre todo mantener esto aquí con un propósito histórico. Utiliza un código ligeramente menor, que a pesar de que se trata del gasto de tener menos rango, porque usa hexadecimal en lugar de base64, se necesitan más caracteres para representar el mismo rango en comparación con las otras soluciones.

Lo que significa más posibilidades de colisión: probarlo con 100,000 iteraciones de 8 cadenas de caracteres generó un duplicado.


160
2017-08-28 00:00



Aquí hay un ejemplo que robé del ejemplo de Sam Allen en Dot Net Perls

Si solo necesita 8 caracteres, use Path.GetRandomFileName () en el espacio de nombres System.IO. Sam dice que usar el método "Path.GetRandomFileName aquí es a veces superior, porque usa RNGCryptoServiceProvider para una mejor aleatoriedad. Sin embargo, está limitado a 11 caracteres aleatorios".

GetRandomFileName siempre devuelve una cadena de 12 caracteres con un punto en el noveno carácter. Por lo tanto, necesitará quitar el período (ya que no es aleatorio) y luego tomar 8 caracteres de la cadena. En realidad, puedes tomar los primeros 8 caracteres y no preocuparte por el período.

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

PD: gracias Sam


52
2017-08-27 23:36



Los principales objetivos de mi código son:

  1. La distribución de las cadenas es casi uniforme (no se preocupan por desviaciones menores, siempre que sean pequeñas)
  2. Genera más de unos mil millones de cadenas para cada conjunto de argumentos. Generar una cadena de 8 caracteres (~ 47 bits de entropía) no tiene sentido si su PRNG solo genera valores diferentes de 2 billones (31 bits de entropía).
  3. Es seguro, ya que espero que las personas lo usen para contraseñas u otros tokens de seguridad.

La primera propiedad se logra tomando un módulo de valor de 64 bit el tamaño del alfabeto. Para los pequeños alfabetos (como los 62 caracteres de la pregunta) esto lleva a un sesgo insignificante. La segunda y tercera propiedad se logran mediante el uso de RNGCryptoServiceProvider en lugar 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



Lo más simple:

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

Puede obtener un mejor rendimiento si codifica la matriz de caracteres y confía en System.Random:

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

Si alguna vez te preocupas, los alfabetos en inglés pueden cambiar en algún momento y podrías perder el negocio, entonces puedes evitar la codificación difícil, pero debería funcionar un poco peor (comparable a Path.GetRandomFileName enfoque)

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);
}

Los dos últimos enfoques se ven mejor si puede convertirlos en un método de extensión en System.Random ejemplo.


28
2018-04-13 07:09



Solo algunas comparaciones de rendimiento de las diversas respuestas en este hilo:

Métodos y configuración

// 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);
}

Resultados

Probado en LinqPad. Para un tamaño de cadena de 10, genera:

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

Y las cifras de rendimiento tienden a variar ligeramente, muy ocasionalmente NonOptimized es realmente más rápido, y a veces ForLoop y GenerateRandomString cambiar quién está a la cabeza.

  • LinqIsTheNewBlack (10000x) = 96762 ticks transcurridos (9.6762 ms)
  • ForLoop (10000x) = 28970 tics transcurridos (2.897 ms)
  • ForLoopNonOptimized (10000x) = 33336 ticks transcurridos (3,3336 ms)
  • Repetir (10000x) = 78547 ticks transcurridos (7.8547 ms)
  • GenerateRandomString (10000x) = 27416 ticks transcurridos (2.7416 ms)
  • SecureFastRandom (10000x) = 13176 ticks transcurridos (5ms) más bajo [Máquina diferente]
  • SecureFastRandom-NoCache (10000x) = 39541 ticks transcurridos (17ms) más bajo [Máquina diferente]

17
2018-06-13 16:45