可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This question already has answers here:
Closed 4 years ago.
I've developed a random string generator but it's not behaving quite as I'm hoping. My goal is to be able to run this twice and generate two distinct four character random strings. However, it just generates one four character random string twice.
Here's the code and an example of its output:
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;
...and the output looks like this: UNTE-UNTE
...but it should look something like this UNTE-FWNU
How can I ensure two distinctly random strings?
回答1:
You're making the Random instance in the method, which causes it to return the same values when called in quick succession. I would do something like this:
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;
(modified version of your code)
回答2:
You're instantiating the Random
object inside your method.
The Random
object is seeded from the system clock, which means that if you call your method several times in quick succession it'll use the same seed each time, which means that it'll generate the same sequence of random numbers, which means that you'll get the same string.
To solve the problem, move your Random
instance outside of the method itself (and while you're at it you could get rid of that crazy sequence of calls to Convert
and Floor
and 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);
}
回答3:
//A very Simple implementation
using System.IO;
public static string RandomStr()
{
string rStr = Path.GetRandomFileName();
rStr = rStr.Replace(".", ""); // For Removing the .
return rStr;
}
//Now just call RandomStr() Method
回答4:
As long as you are using Asp.Net 2.0 or greater, you can also use the library call-
System.Web.Security.Membership.GeneratePassword
, however it will include special characters.
To get 4 random characters with minimum of 0 special characters-
Membership.GeneratePassword(4, 0)
回答5:
Just for people stopping by and what to have a random string in just one single line of code
int yourRandomStringLength = 12; //maximum: 32
Guid.NewGuid().ToString("N").Substring(0, yourRandomStringLength);
PS: Please keep in mind that yourRandomStringLength
cannot exceed 32 as Guid
has max length of 32.
回答6:
This solution is an extension for a Random
class.
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}_-"
}
}
Implementation
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);
}
}
回答7:
Yet another version of string generator. Simple, without fancy math and magic digits. But with some magic string which specifies allowed characters.
Update:
I made generator static, so it will not return same string when called multiple times. However this code is not thread-safe and is definitely not cryptographically secure.
For password generation System.Security.Cryptography.RNGCryptoServiceProvider
should be used.
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();
}
回答8:
Here is one more 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());
}
}
回答9:
The best solution is using the random number generator toghether with base64 conversion
public string GenRandString(int length)
{
byte[] randBuffer = new byte[length];
RandomNumberGenerator.Create().GetBytes(randBuffer);
return System.Convert.ToBase64String(randBuffer).Remove(length);
}
回答10:
This is because each new instance of Random is generating the same numbers from being called so fast. Do not keep creating a new instance, just call next() and declare your random class outside of your method.
回答11:
A LINQ one-liner for good measure (assuming a private static Random Random
)...
public static string RandomString(int length)
{
return new string(Enumerable.Range(0, length).Select(_ => (char)Random.Next('a', 'z')).ToArray());
}
回答12:
You should have one class-level Random object initiated once in the constructor and reused on each call (this continues the same sequence of pseudo-random numbers). The parameterless constructor already seeds the generator with Environment.TickCount internally.
回答13:
If you wanted to generate a string of Numbers and Characters for a strong password.
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();
}
回答14:
I added the option to choose the length using the Ranvir solution
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);
}
}
回答15:
Here is my modification of the currently accepted answer, which I believe it's a little faster and shorter:
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();
}
Notice I didn't use all the multiplication, Math.floor()
, Convert
etc.
EDIT: random.Next(0x41, 0x5A)
can be changed to any range of Unicode characters.
回答16:
My RandomString()
method to generate a random string.
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);
}
回答17:
I think may be this is also acceptable and simple.
Guid.NewGuid().ToString()
回答18:
Combining the answer by "Pushcode" and the one using the seed for the random generator. I needed it to create a serie of pseudo-readable 'words'.
private int RandomNumber(int min, int max, int seed=0)
{
Random random = new Random((int)DateTime.Now.Ticks + seed);
return random.Next(min, max);
}
回答19:
I created this method.
It works great.
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;
}
回答20:
And here is another idea based on GUIDs. I've used it for the Visual Studio performance test to generate random string contaning only alphanumeric characters.
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);
}
回答21:
Here is a blog post that provides a bit more robust class for generating random words, sentences and paragraphs.
回答22:
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;
}
}
You also will need this:
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;
}
}
And this:
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);
}
}
回答23:
Actually, a good solution is to have a static method for the random number generator that is thread-safe and doesn't use locks.
That way, multiple users accessing your web application at the same time don't get the same random strings.
There are 3 examples here:
http://blogs.msdn.com/b/pfxteam/archive/2009/02/19/9434171.aspx
I'd use the last one:
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();
}
}
Then you can properly eliminate
Random random = new Random();
And just call RandomGen3.Next(), while your method can remain static.
回答24:
For random string generator :
#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
回答25:
I found this to be more helpfull, since it is an extention, and it allows you to select the source of your 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 };
Hope this helps.
回答26:
In my situation, the password must contain:
- At least one lower case.
- At least one upper case.
- At least one decimal.
- At least one special character.
Here is my 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;
}
回答27:
Hello
you can use WordGenerator or LoremIpsumGenerator from MMLib.RapidPrototyping nuget package.
using MMLib.RapidPrototyping.Generators;
public void WordGeneratorExample()
{
WordGenerator generator = new WordGenerator();
var randomWord = generator.Next();
Console.WriteLine(randomWord);
}
Nuget site
Codeplex project site
回答28:
If you have access to an Intel Secure Key compatible CPU, you can generate real random numbers and strings using these libraries: https://github.com/JebteK/RdRand and https://www.rdrand.com/
Just download the latest version from here, include Jebtek.RdRand and add a using statement for it. Then, all you need to do is this:
bool isAvailable = RdRandom.GeneratorAvailable(); //Check to see if this is a compatible CPU
string key = RdRandom.GenerateKey(10); //Generate 10 random characters
Plus, you also get these additional capabilities:
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
If you don't have a compatible CPU to execute the code on, just use the RESTful services at rdrand.com. With the RdRandom wrapper library included in your project, you would just need to do this (you get 1000 free calls when you signup):
string ret = Randomizer.GenerateKey(<length>, "<key>");
You can also generate random byte arrays and unsigned integers as follows:
uint ret = Randomizer.GenerateUInt("<key>");
byte[] ret = Randomizer.GenerateBytes(<length>, "<key>");
回答29:
Another sample (tested in 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);
Implemented by myself.
回答30:
This is my 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;