it-swarm-es.tech

¿Cómo puedo generar cadenas alfanuméricas al azar?

¿Cómo puedo generar una cadena alfanumérica de 8 caracteres al azar en C #?

813
KingNestor

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 no sea adecuado para cualquier cosa relacionada con la seguridad , como la creación de contraseñas o tokens. Use la clase RNGCryptoServiceProvider si necesita un generador de números aleatorios seguro.)

1474
dtb
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 Linq.

(Nota: el uso de la clase Random hace que no sea adecuado para cualquier cosa relacionada con la seguridad , como la creación de contraseñas o tokens. Use la clase RNGCryptoServiceProvider si necesita un generador de números aleatorios seguro.)

326
Dan Rigby

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

A diferencia de algunas de las alternativas presentadas, esta es criptográficamente sólida .

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

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

Lo escogí de una discusión de alternativas aquí

291
Eric J.

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 rango que usar un GUID porque un GUID tiene un par de bits fijos que son siempre iguales y, por lo tanto, no aleatorios, por ejemplo, el carácter de 13 caracteres en hexadecimal siempre es " 4 "- al menos en una versión 6 GUID.

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 puede generar cadenas siempre y cuando Solución 1 y la cadena no tenga el mismo rango debido a los bits fijos en los GUID, pero en muchos casos esto hará el trabajo.

Solución 3 - Un poco menos de código

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

Principalmente manteniendo esto aquí para propósitos históricos. Utiliza un poco menos de código, aunque eso implica el costo de tener menos rango, ya que usa hex 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.

184
Douglas

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. Así que tendrás que 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

58
Adam Porad

Los principales objetivos de mi código son:

  1. La distribución de las cuerdas es casi uniforme (no importa las desviaciones menores, siempre que sean pequeñas)
  2. Produce más de unos pocos miles de millones de cadenas para cada conjunto de argumentos. La generación de una cadena de 8 caracteres (~ 47 bits de entropía) no tiene sentido si su PRNG solo genera 2 mil millones (31 bits de entropía) valores diferentes.
  3. Es seguro, ya que espero que la gente use esto para contraseñas u otros tokens de seguridad.

La primera propiedad se logra al tomar un valor de 64 bits en el tamaño del alfabeto. Para alfabetos pequeños (como los 62 caracteres de la pregunta) esto lleva a un sesgo insignificante. La segunda y tercera propiedad se logran utilizando 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];
    var result = new char[length];
    using (var cryptoProvider = new RNGCryptoServiceProvider())
    {
        cryptoProvider.GetBytes(bytes);
    }
    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);
}
35
CodesInChaos

Lo más simple:

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

Puede obtener un mejor rendimiento si codifica la matriz char 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ías tener un rendimiento algo peor (comparable al enfoque Path.GetRandomFileName)

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 la instancia de System.Random.

29
nawfal

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 el tamaño de cadena de 10, genera:

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

Y los números de rendimiento tienden a variar ligeramente, muy ocasionalmente NonOptimized es en realidad más rápido, y a veces ForLoop y GenerateRandomString cambian quién está a la cabeza.

  • LinqIsTheNewBlack (10000x) = 96762 ticks transcurridos (9.6762 ms)
  • ForLoop (10000x) = 28970 ticks transcurridos (2.897 ms)
  • ForLoopNonOptimized (10000x) = 33336 tics 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 bajos [Máquina diferente]
20
drzaus

Una línea de código Membership.GeneratePassword() hace el truco :)

Aquí hay una demo para el mismo.

17
Pooran

El código escrito por Eric J. es bastante descuidado (es bastante claro que es de hace 6 años ... probablemente no escribiría ese código hoy), e incluso hay algunos problemas.

A diferencia de algunas de las alternativas presentadas, esta es criptográficamente sólida.

Falso ... Hay un sesgo en la contraseña (como está escrito en un comentario), bcdefgh es un poco más probable que las otras (la a no es porque por la GetNonZeroBytes no genera bytes con un valor de cero, por lo que el sesgo de la a se equilibra con ella), por lo que no es realmente criptográficamente sólido.

Esto debería corregir todos los problemas.

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

Pregunta: ¿Por qué debería perder mi tiempo usando Enumerable.Range en lugar de escribir "ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789"?

using System;
using System.Collections.Generic;
using System.Linq;

public class Test
{
    public static void Main()
    {
        var randomCharacters = GetRandomCharacters(8, true);
        Console.WriteLine(new string(randomCharacters.ToArray()));
    }

    private static List<char> getAvailableRandomCharacters(bool includeLowerCase)
    {
        var integers = Enumerable.Empty<int>();
        integers = integers.Concat(Enumerable.Range('A', 26));
        integers = integers.Concat(Enumerable.Range('0', 10));

        if ( includeLowerCase )
            integers = integers.Concat(Enumerable.Range('a', 26));

        return integers.Select(i => (char)i).ToList();
    }

    public static IEnumerable<char> GetRandomCharacters(int count, bool includeLowerCase)
    {
        var characters = getAvailableRandomCharacters(includeLowerCase);
        var random = new Random();
        var result = Enumerable.Range(0, count)
            .Select(_ => characters[random.Next(characters.Count)]);

        return result;
    }
}

Respuesta: Las cadenas mágicas son MALAS. ¿Alguien notó que no había "I" en mi cadena en la parte superior? Mi madre me enseñó a no usar cuerdas mágicas por esta razón ...

nótese bien. 1: Como muchos otros como @dtb dijeron, no use System.Random si necesita seguridad criptográfica ...

nótese bien. 2: Esta respuesta no es la más eficiente ni la más corta, pero quería que el espacio separara la respuesta de la pregunta. El propósito de mi respuesta es más advertir contra las cuerdas mágicas que proporcionar una respuesta innovadora y elegante.

6
Wai Ha Lee

También usamos cadenas aleatorias personalizadas, pero implementamos como un ayudante de cadenas, por lo que proporciona cierta flexibilidad ...

public static string Random(this string chars, int length = 8)
{
    var randomString = new StringBuilder();
    var random = new Random();

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

    return randomString.ToString();
}

Uso

var random = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".Random();

o

var random = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".Random(16);
6
Mr. Pumpkin

Otra opción podría ser usar Linq y agregar caracteres aleatorios en un constructor de cadenas.

var chars = "abcdefghijklmnopqrstuvwxyz123456789".ToArray();
string pw = Enumerable.Range(0, passwordLength)
                      .Aggregate(
                          new StringBuilder(),
                          (sb, n) => sb.Append((chars[random.Next(chars.Length)])),
                          sb => sb.ToString());
6
AAD

Mi simple código de una línea funciona para mí :)

string  random = string.Join("", Guid.NewGuid().ToString("n").Take(8).Select(o => o));

Response.Write(random.ToUpper());
Response.Write(random.ToLower());

Para expandir esto para cualquier cadena de longitud

    public static string RandomString(int length)
    {
        //length = length < 0 ? length * -1 : length;
        var str = "";

        do 
        {
            str += Guid.NewGuid().ToString().Replace("-", "");
        }

        while (length > str.Length);

        return str.Substring(0, length);
    }
6
Raj kumar

Después de revisar las otras respuestas y considerar los comentarios de CodeInChaos, junto con CodeInChaos todavía sesgada (aunque menos), pensé que una solución final definitiva de cortar y pegar era necesario. Entonces, mientras actualizaba mi respuesta, decidí hacer todo lo posible.

Para obtener una versión actualizada de este código, visite el nuevo repositorio de Hg en Bitbucket: https://bitbucket.org/merarischroeder/secureswiftrandom . Te recomiendo copiar y pegar el código de: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRandom.cs?at=default&fileviewer=file-view-default (asegúrese de hacer clic en el botón Sin formato para que sea más fácil de copiar y asegúrese de tener la última versión, creo que este enlace va a una versión específica del código, no a la última).

Notas actualizadas:

  1. Relacionado con algunas otras respuestas: si conoce la longitud de la salida, no necesita un StringBuilder, y cuando usa ToCharArray, esto crea y llena la matriz (no necesita crear primero una matriz vacía)
  2. En relación con algunas otras respuestas: debe usar NextBytes, en lugar de obtener una por vez para el rendimiento
  3. Técnicamente, podría anclar la matriz de bytes para un acceso más rápido ... generalmente vale la pena cuando itera más de 6-8 veces sobre una matriz de bytes. (No hecho aquí)
  4. Uso de RNGCryptoServiceProvider para la mejor aleatoriedad
  5. Uso del almacenamiento en caché de un búfer de 1 MB de datos aleatorios : la evaluación comparativa muestra que la velocidad de acceso de bytes individuales en caché es ~ 1000 veces más rápida, tardando 9 ms en 1 MB frente a 989 ms para el almacenamiento en caché.
  6. Rechazo optimizado de la zona de sesgo dentro de mi nueva clase.

Solución final a la pregunta:

static char[] charSet =  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
static int byteSize = 256; //Labelling convenience
static int biasZone = byteSize - (byteSize % charSet.Length);
public string GenerateRandomString(int Length) //Configurable output string length
{
    byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
    char[] rName = new char[Length];
    SecureFastRandom.GetNextBytesMax(rBytes, biasZone);
    for (var i = 0; i < Length; i++)
    {
        rName[i] = charSet[rBytes[i] % charSet.Length];
    }
    return new string(rName);
}

Pero necesitas mi nueva clase (no probada):

/// <summary>
/// My benchmarking showed that for RNGCryptoServiceProvider:
/// 1. There is negligable benefit of sharing RNGCryptoServiceProvider object reference 
/// 2. Initial GetBytes takes 2ms, and an initial read of 1MB takes 3ms (starting to rise, but still negligable)
/// 2. Cached is ~1000x faster for single byte at a time - taking 9ms over 1MB vs 989ms for uncached
/// </summary>
class SecureFastRandom
{
    static byte[] byteCache = new byte[1000000]; //My benchmark showed that an initial read takes 2ms, and an initial read of this size takes 3ms (starting to raise)
    static int lastPosition = 0;
    static int remaining = 0;

    /// <summary>
    /// Static direct uncached access to the RNGCryptoServiceProvider GetBytes function
    /// </summary>
    /// <param name="buffer"></param>
    public static void DirectGetBytes(byte[] buffer)
    {
        using (var r = new RNGCryptoServiceProvider())
        {
            r.GetBytes(buffer);
        }
    }

    /// <summary>
    /// Main expected method to be called by user. Underlying random data is cached from RNGCryptoServiceProvider for best performance
    /// </summary>
    /// <param name="buffer"></param>
    public static void GetBytes(byte[] buffer)
    {
        if (buffer.Length > byteCache.Length)
        {
            DirectGetBytes(buffer);
            return;
        }

        lock (byteCache)
        {
            if (buffer.Length > remaining)
            {
                DirectGetBytes(byteCache);
                lastPosition = 0;
                remaining = byteCache.Length;
            }

            Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
            lastPosition += buffer.Length;
            remaining -= buffer.Length;
        }
    }

    /// <summary>
    /// Return a single byte from the cache of random data.
    /// </summary>
    /// <returns></returns>
    public static byte GetByte()
    {
        lock (byteCache)
        {
            return UnsafeGetByte();
        }
    }

    /// <summary>
    /// Shared with public GetByte and GetBytesWithMax, and not locked to reduce lock/unlocking in loops. Must be called within lock of byteCache.
    /// </summary>
    /// <returns></returns>
    static byte UnsafeGetByte()
    {
        if (1 > remaining)
        {
            DirectGetBytes(byteCache);
            lastPosition = 0;
            remaining = byteCache.Length;
        }

        lastPosition++;
        remaining--;
        return byteCache[lastPosition - 1];
    }

    /// <summary>
    /// Rejects bytes which are equal to or greater than max. This is useful for ensuring there is no bias when you are modulating with a non power of 2 number.
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="max"></param>
    public static void GetBytesWithMax(byte[] buffer, byte max)
    {
        if (buffer.Length > byteCache.Length / 2) //No point caching for larger sizes
        {
            DirectGetBytes(buffer);

            lock (byteCache)
            {
                UnsafeCheckBytesMax(buffer, max);
            }
        }
        else
        {
            lock (byteCache)
            {
                if (buffer.Length > remaining) //Recache if not enough remaining, discarding remaining - too much work to join two blocks
                    DirectGetBytes(byteCache);

                Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
                lastPosition += buffer.Length;
                remaining -= buffer.Length;

                UnsafeCheckBytesMax(buffer, max);
            }
        }
    }

    /// <summary>
    /// Checks buffer for bytes equal and above max. Must be called within lock of byteCache.
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="max"></param>
    static void UnsafeCheckBytesMax(byte[] buffer, byte max)
    {
        for (int i = 0; i < buffer.Length; i++)
        {
            while (buffer[i] >= max)
                buffer[i] = UnsafeGetByte(); //Replace all bytes which are equal or above max
        }
    }
}

Para el historial: mi solución anterior para esta respuesta, utilizaba un objeto aleatorio:

    private static char[] charSet =
      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();

    static rGen = new Random(); //Must share, because the clock seed only has Ticks (~10ms) resolution, yet lock has only 20-50ns delay.
    static int byteSize = 256; //Labelling convenience
    static int biasZone = byteSize - (byteSize % charSet.Length);
    static bool SlightlyMoreSecurityNeeded = true; //Configuration - needs to be true, if more security is desired and if charSet.Length is not divisible by 2^X.
    public string GenerateRandomString(int Length) //Configurable output string length
    {
      byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
      char[] rName = new char[Length];
      lock (rGen) //~20-50ns
      {
          rGen.NextBytes(rBytes);

          for (int i = 0; i < Length; i++)
          {
              while (SlightlyMoreSecurityNeeded && rBytes[i] >= biasZone) //Secure against 1/5 increased bias of index[0-7] values against others. Note: Must exclude where it == biasZone (that is >=), otherwise there's still a bias on index 0.
                  rBytes[i] = rGen.NextByte();
              rName[i] = charSet[rBytes[i] % charSet.Length];
          }
      }
      return new string(rName);
    }

Actuación:

  1. SecureFastRandom - Primera ejecución individual = ~ 9-33ms . Imperceptible. En curso : 5 ms (a veces sube hasta 13 ms) durante 10.000 iteraciones, con una única iteración promedio = 1.5 microsegundos. . Nota: Requiere generalmente 2, pero ocasionalmente hasta 8 actualizaciones de caché; depende de cuántos bytes individuales excedan la zona de sesgo
  2. Aleatorio - Primera ejecución individual = ~ 0-1ms . Imperceptible. En curso : 5 ms más de 10,000 iteraciones. Con una sola iteración promedio = . 5 microsegundos. . Sobre la misma velocidad.

También echa un vistazo a:

Estos enlaces son otro enfoque. El almacenamiento en búfer podría agregarse a esta nueva base de código, pero lo más importante fue explorar diferentes enfoques para eliminar el sesgo y comparar las velocidades y las ventajas y desventajas.

5
Merari Schroeder

Una versión ligeramente más limpia de la solución de DTB.

    var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    var random = new Random();
    var list = Enumerable.Repeat(0, 8).Select(x=>chars[random.Next(chars.Length)]);
    return string.Join("", list);

Tus preferencias de estilo pueden variar.

5
Rob Deary

Estaba buscando una respuesta más específica, donde quiero controlar el formato de la cadena aleatoria y encontré esta publicación. Por ejemplo: las matrículas (de los automóviles) tienen un formato específico (por país) y yo quería crear matrículas al azar.
Decidí escribir mi propio método de extensión de Random para esto. (Esto es para reutilizar el mismo objeto aleatorio, ya que podría duplicarse en escenarios de subprocesos múltiples). Creé un Gist ( https://Gist.github.com/SamVanhoutte/808845ca78b9c041e928 ), pero también copiaré la clase de extensión aquí:

void Main()
{
    Random rnd = new Random();
    rnd.GetString("1-###-000").Dump();
}

public static class RandomExtensions
{
    public static string GetString(this Random random, string format)
    {
        // Based on http://stackoverflow.com/questions/1344221/how-can-i-generate-random-alphanumeric-strings-in-c
        // Added logic to specify the format of the random string (# will be random string, 0 will be random numeric, other characters remain)
        StringBuilder result = new StringBuilder();
        for(int formatIndex = 0; formatIndex < format.Length ; formatIndex++)
        {
            switch(format.ToUpper()[formatIndex])
            {
                case '0': result.Append(getRandomNumeric(random)); break;
                case '#': result.Append(getRandomCharacter(random)); break;
                default : result.Append(format[formatIndex]); break;
            }
        }
        return result.ToString();
    }

    private static char getRandomCharacter(Random random)
    {
        string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        return chars[random.Next(chars.Length)];
    }

    private static char getRandomNumeric(Random random)
    {
        string nums = "0123456789";
        return nums[random.Next(nums.Length)];
    }
}
4
Sam Vanhoutte

Horrible, lo sé, pero no pude evitarlo:


namespace ConsoleApplication2
{
    using System;
    using System.Text.RegularExpressions;

    class Program
    {
        static void Main(string[] args)
        {
            Random adomRng = new Random();
            string rndString = string.Empty;
            char c;

            for (int i = 0; i < 8; i++)
            {
                while (!Regex.IsMatch((c=Convert.ToChar(adomRng.Next(48,128))).ToString(), "[A-Za-z0-9]"));
                rndString += c;
            }

            Console.WriteLine(rndString + Environment.NewLine);
        }
    }
}
4
james
 public static string RandomString(int length)
    {
        const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        var random = new Random();
        return new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());
    }
4
Tejas

Intenta combinar dos partes: única (secuencia, contador o fecha) y aleatoria

public class RandomStringGenerator
{
    public static string Gen()
    {
        return ConvertToBase(DateTime.UtcNow.ToFileTimeUtc()) + GenRandomStrings(5); //keep length fixed at least of one part
    }

    private static string GenRandomStrings(int strLen)
    {
        var result = string.Empty;

        var Gen = new RNGCryptoServiceProvider();
        var data = new byte[1];

        while (result.Length < strLen)
        {
            Gen.GetNonZeroBytes(data);
            int code = data[0];
            if (code > 48 && code < 57 || // 0-9
                code > 65 && code < 90 || // A-Z
                code > 97 && code < 122   // a-z
                )
            {
                result += Convert.ToChar(code);
            }
        }

        return result;
    }

    private static string ConvertToBase(long num, int nbase = 36)
    {
        var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //if you wish make algoritm more secure - change order of letter here

        // check if we can convert to another base
        if (nbase < 2 || nbase > chars.Length)
            return null;

        int r;
        var newNumber = string.Empty;

        // in r we have the offset of the char that was converted to the new base
        while (num >= nbase)
        {
            r = (int) (num % nbase);
            newNumber = chars[r] + newNumber;
            num = num / nbase;
        }
        // the last number to convert
        newNumber = chars[(int)num] + newNumber;

        return newNumber;
    }
}

Pruebas:

[Test]
    public void Generator_Should_BeUnigue1()
    {
        //Given
        var loop = Enumerable.Range(0, 1000);
        //When
        var str = loop.Select(x=> RandomStringGenerator.Gen());
        //Then
        var distinct = str.Distinct();
        Assert.AreEqual(loop.Count(),distinct.Count()); // Or Assert.IsTrue(distinct.Count() < 0.95 * loop.Count())
    }
3
RouR

Ahora en sabor de una sola línea.

private string RandomName
    {
        get
        {
            return new string(
                Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13)
                    .Select(s =>
                    {
                        var cryptoResult = new byte[4];
                        using (var cryptoProvider = new RNGCryptoServiceProvider())
                            cryptoProvider.GetBytes(cryptoResult);
                        return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)];
                    })
                    .ToArray());
        }
    }
2
Matas Vaitkevicius

Aquí hay una variante de la solución de Eric J, es decir, criptográficamente sólida, para WinRT (aplicación de la tienda de Windows):

public static string GenerateRandomString(int length)
{
    var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    var result = new StringBuilder(length);
    for (int i = 0; i < length; ++i)
    {
        result.Append(CryptographicBuffer.GenerateRandomNumber() % chars.Length);
    }
    return result.ToString();
}

Si el rendimiento importa (especialmente cuando la longitud es alta):

public static string GenerateRandomString(int length)
{
    var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    var result = new System.Text.StringBuilder(length);
    var bytes = CryptographicBuffer.GenerateRandom((uint)length * 4).ToArray();
    for (int i = 0; i < bytes.Length; i += 4)
    {
        result.Append(BitConverter.ToUInt32(bytes, i) % chars.Length);
    }
    return result.ToString();
}
2
huyc

Una solución sin usar Random:

var chars = Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 8);

var randomStr = new string(chars.SelectMany(str => str)
                                .OrderBy(c => Guid.NewGuid())
                                .Take(8).ToArray());
2
w.b

No sé qué tan criptográficamente es esto, pero es más legible y conciso que las soluciones más complejas por el momento (imo), y debería ser más "aleatorio" que las soluciones basadas en System.Random-.

return alphabet
    .OrderBy(c => Guid.NewGuid())
    .Take(strLength)
    .Aggregate(
        new StringBuilder(),
        (builder, c) => builder.Append(c))
    .ToString();

No puedo decidir si creo que esta versión o la siguiente es "más bonita", pero dan exactamente los mismos resultados:

return new string(alphabet
    .OrderBy(o => Guid.NewGuid())
    .Take(strLength)
    .ToArray());

Por supuesto, no está optimizado para la velocidad, por lo que si es fundamental para la misión generar millones de cadenas aleatorias cada segundo, ¡intente con otra!

NOTA: Esta solución no permite la repetición de símbolos en el alfabeto, y el alfabeto DEBE ser de igual o mayor tamaño que la cadena de salida, lo que hace que este enfoque sea menos deseable en algunas circunstancias, todo depende de su caso de uso.

1
sara

Sé que esta no es la mejor manera. Pero puedes intentar esto.

string str = Path.GetRandomFileName(); //This method returns a random file name of 11 characters
str = str.Replace(".","");
Console.WriteLine("Random string: " + str);
1
Sagar

Si sus valores no son completamente aleatorios, pero de hecho puede depender de algo, puede calcular un hash md5 o sha1 de ese 'algo' y luego truncarlo a la longitud que desee.

También puedes generar y truncar un guid.

0
Alexey B.

Aquí hay un mecanismo para generar una cadena alfanumérica aleatoria (yo uso esto para generar contraseñas y datos de prueba) sin definir el alfabeto y los números,

CleanupBase64 eliminará las partes necesarias en la cadena y seguirá agregando letras alfanuméricas aleatorias de forma recursiva.

        public static string GenerateRandomString(int length)
        {
            var numArray = new byte[length];
            new RNGCryptoServiceProvider().GetBytes(numArray);
            return CleanUpBase64String(Convert.ToBase64String(numArray), length);
        }

        private static string CleanUpBase64String(string input, int maxLength)
        {
            input = input.Replace("-", "");
            input = input.Replace("=", "");
            input = input.Replace("/", "");
            input = input.Replace("+", "");
            input = input.Replace(" ", "");
            while (input.Length < maxLength)
                input = input + GenerateRandomString(maxLength);
            return input.Length <= maxLength ?
                input.ToUpper() : //In my case I want capital letters
                input.ToUpper().Substring(0, maxLength);
        }
0
Dhanuka777
public static class StringHelper
{
    private static readonly Random random = new Random();

    private const int randomSymbolsDefaultCount = 8;
    private const string availableChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    private static int randomSymbolsIndex = 0;

    public static string GetRandomSymbols()
    {
        return GetRandomSymbols(randomSymbolsDefaultCount);
    }

    public static string GetRandomSymbols(int count)
    {
        var index = randomSymbolsIndex;
        var result = new string(
            Enumerable.Repeat(availableChars, count)
                      .Select(s => {
                          index += random.Next(s.Length);
                          if (index >= s.Length)
                              index -= s.Length;
                          return s[index];
                      })
                      .ToArray());
        randomSymbolsIndex = index;
        return result;
    }
}
0
KregHEk