c# - ruleta - Generador de cadenas aleatorias que devuelve la misma cadena
letras aleatorias para stop (30)
Esta pregunta ya tiene una respuesta aquí:
He desarrollado un generador de cadenas aleatorias, pero no se está comportando como esperaba. Mi objetivo es poder ejecutar esto dos veces y generar dos cadenas distintas de cuatro caracteres aleatorios. Sin embargo, solo genera una cadena aleatoria de cuatro caracteres dos veces.
Aquí está el código y un ejemplo de su salida:
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;
... y la salida se ve así: UNTE-UNTE ... pero debería verse así: UNTE-FWNU
¿Cómo puedo asegurar dos cadenas claramente aleatorias?
// Una implementación muy simple
using System.IO;
public static string RandomStr()
{
string rStr = Path.GetRandomFileName();
rStr = rStr.Replace(".", ""); // For Removing the .
return rStr;
}
// Ahora solo llama al método RandomStr ()
Agregué la opción de elegir la longitud usando la solución 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);
}
}
Aquí está mi modificación de la respuesta actualmente aceptada, que creo que es un poco más rápida y más corta:
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();
}
Note que no Math.floor()
toda la multiplicación, Math.floor()
, Convert
, etc.
EDIT: random.Next(0x41, 0x5A)
se puede cambiar a cualquier rango de caracteres Unicode.
Aquí hay una opción más:
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());
}
}
Combinando la respuesta con "Pushcode" y la que usa la semilla para el generador aleatorio. Lo necesitaba para crear una serie de ''palabras'' pseudo-legibles.
private int RandomNumber(int min, int max, int seed=0)
{
Random random = new Random((int)DateTime.Now.Ticks + seed);
return random.Next(min, max);
}
Creo que puede ser esto también es aceptable y simple.
Guid.NewGuid().ToString()
Debe tener un objeto aleatorio de nivel de clase iniciado una vez en el constructor y reutilizado en cada llamada (esto continúa con la misma secuencia de números pseudoaleatorios). El constructor sin parámetros ya siembra el generador con Environment.TickCount internamente.
En mi situación, la contraseña debe contener:
- Al menos una minúscula.
- Al menos una mayúscula.
- Al menos un decimal.
- Al menos un personaje especial.
Aquí está mi código:
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;
}
En realidad, una buena solución es tener un método estático para el generador de números aleatorios que sea seguro para subprocesos y no use bloqueos.
De esa manera, varios usuarios que acceden a su aplicación web al mismo tiempo no obtienen las mismas cadenas aleatorias.
Hay 3 ejemplos aquí: http://blogs.msdn.com/b/pfxteam/archive/2009/02/19/9434171.aspx
Yo usaría el último:
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();
}
}
Entonces puedes eliminar adecuadamente
Random random = new Random();
Y solo llame a RandomGen3.Next (), mientras que su método puede permanecer estático.
Encontré que esto es más útil, ya que es una extensión, y te permite seleccionar la fuente de tu código.
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 };
Espero que esto ayude.
Está creando la instancia aleatoria en el método, lo que hace que devuelva los mismos valores cuando se le llama en rápida sucesión. Haría algo como esto:
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;
(versión modificada de su código)
Estás creando una instancia del objeto Random
dentro de tu método.
El objeto Random
se siembra del reloj del sistema , lo que significa que si llama a su método varias veces en una sucesión rápida, usará la misma semilla cada vez, lo que significa que generará la misma secuencia de números aleatorios, lo que significa que obtendrá la misma cadena.
Para resolver el problema, mueva su instancia Random
fuera del método en sí (y mientras lo hace, puede deshacerse de esa secuencia loca de llamadas a Convert
y Floor
y 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);
}
Esta es mi solución:
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;
Esta solución es una extensión para una clase Random
.
Uso
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}_-"
}
}
Implementación
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);
}
}
Esto se debe a que cada nueva instancia de Random está generando que los mismos números se llamen tan rápido. No siga creando una nueva instancia, solo llame a next () y declare su clase aleatoria fuera de su método.
He creado este método.
Funciona muy 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;
}
Hola
puede usar WordGenerator o LoremIpsumGenerator del paquete nuget MMLib.RapidPrototyping.
using MMLib.RapidPrototyping.Generators;
public void WordGeneratorExample()
{
WordGenerator generator = new WordGenerator();
var randomWord = generator.Next();
Console.WriteLine(randomWord);
}
La mejor solución es usar el generador de números aleatorios junto con la conversión de base64
public string GenRandString(int length)
{
byte[] randBuffer = new byte[length];
RandomNumberGenerator.Create().GetBytes(randBuffer);
return System.Convert.ToBase64String(randBuffer).Remove(length);
}
Mi método RandomString()
para generar una cadena aleatoria.
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);
}
Mientras esté usando Asp.Net 2.0 o superior, también puede usar la biblioteca llamada System.Web.Security.Membership.GeneratePassword
, sin embargo, incluirá caracteres especiales.
Para obtener 4 caracteres aleatorios con un mínimo de 0 caracteres especiales-
Membership.GeneratePassword(4, 0)
Otra versión más del generador de cuerdas. Sencillo, sin matemáticas de fantasía y dígitos mágicos. Pero con alguna cadena mágica que especifica caracteres permitidos.
Actualización: hice el generador estático, por lo que no devolverá la misma cadena cuando se llame varias veces. Sin embargo, este código no es seguro para subprocesos y definitivamente no es criptográficamente seguro .
Para la generación de contraseñas, se debe utilizar System.Security.Cryptography.RNGCryptoServiceProvider
.
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();
}
Para generador de cadenas aleatorias:
#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
Si desea generar una cadena de números y caracteres para una contraseña segura.
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();
}
Si tiene acceso a una CPU compatible con Intel Secure Key, puede generar números y cadenas aleatorios reales utilizando estas bibliotecas: https://github.com/JebteK/RdRand y https://www.rdrand.com/
Solo descargue la última versión desde here , incluya Jebtek.RdRand y agregue una declaración de uso para ello. Entonces, todo lo que necesitas hacer es esto:
bool isAvailable = RdRandom.GeneratorAvailable(); //Check to see if this is a compatible CPU
string key = RdRandom.GenerateKey(10); //Generate 10 random characters
Además, también obtienes estas capacidades adicionales:
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 no tiene una CPU compatible para ejecutar el código, solo use los servicios RESTful en rdrand.com. Con la biblioteca de envoltorio de RdRandom incluida en su proyecto, solo tendría que hacer esto (obtendrá 1000 llamadas gratis cuando se registre):
string ret = Randomizer.GenerateKey(<length>, "<key>");
También puede generar matrices de bytes aleatorias y enteros sin signo de la siguiente manera:
uint ret = Randomizer.GenerateUInt("<key>");
byte[] ret = Randomizer.GenerateBytes(<length>, "<key>");
Solo para personas que se detienen y qué debe tener una cadena aleatoria en una sola línea de código
int yourRandomStringLength = 12; //maximum: 32
Guid.NewGuid().ToString("N").Substring(0, yourRandomStringLength);
PD: Tenga en cuenta que su yourRandomStringLength
no puede superar los 32, ya que Guid
tiene una longitud máxima de 32.
Un LINQ de una sola línea para una buena medida (asumiendo 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());
}
Y aquí hay otra idea basada en GUIDs. Lo he usado para la prueba de rendimiento de Visual Studio para generar cadenas aleatorias que solo contienen caracteres alfanuméricos.
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);
}
Aquí hay una publicación de blog que proporciona una clase un poco más robusta para generar palabras, oraciones y párrafos al azar.
Otra muestra (probada 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);
Implementado por mi mismo.
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;
}
}
También necesitarás esto:
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;
}
}
Y esto:
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);
}
}