关于C#:返回相同字符串的随机字符串生成器

 2019-04-29 

Random String Generator Returning Same String

本问题已经有最佳答案,请猛点这里访问。

我开发了一个随机字符串生成器,但它的性能并不像我希望的那样好。我的目标是能够运行这两次,并生成两个不同的四字符随机字符串。但是,它只生成一个四字符随机字符串两次。

下面是代码及其输出示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;

…输出如下:unt-unte…但看起来应该像这个UNT-FWNU

如何确保两个明显随机的字符串?


您在方法中创建了随机实例,这使得它在快速连续调用时返回相同的值。我会这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;

(代码的修改版本)


您正在实例化方法中的Random对象。

Random对象是从系统时钟中植入的,这意味着如果您连续多次快速调用方法,每次都会使用相同的种子,这意味着它将生成相同的随机数序列,这意味着您将获得相同的字符串。

要解决此问题,请将您的Random实例移出方法本身(当您进行此操作时,您可以消除对ConvertFloorNextDouble的疯狂调用序列):

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
}


//一个非常简单的实现

1
2
3
4
5
6
7
8
using System.IO;  
public static string RandomStr()

{
    string rStr = Path.GetRandomFileName();
    rStr = rStr.Replace(".",""); // For Removing the .
    return rStr;
}

//现在只需调用randomstr()方法


只要使用的是ASP.NET 2.0或更高版本,也可以使用库调用-但是,它将包含特殊字符。

获取至少有0个特殊字符的4个随机字符-

1
Membership.GeneratePassword(4, 0)


只为路过的人以及在一行代码中有随机字符串的内容

1
2
int yourRandomStringLength = 12; //maximum: 32
Guid.NewGuid().ToString("N").Substring(0, yourRandomStringLength);

PS:请记住,yourRandomStringLength不能超过32,因为Guid的最大长度为32。


另一个版本的字符串生成器。简单,没有花哨的数学和神奇的数字。但使用一些指定允许字符的神奇字符串。

更新:我将生成器设置为静态的,因此在多次调用时它不会返回相同的字符串。然而,此代码不是线程安全的,而且绝对不是加密安全的。

对于密码生成,应使用System.Security.Cryptography.RNGCryptoServiceProvider

1
2
3
4
5
6
7
8
9
10
11
12
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();
}


此解决方案是Random类的扩展。

用法

1
2
3
4
5
6
7
8
9
10
11
12
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}_-"
    }
}

实施

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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);
    }
}


这里还有一个选择:

1
2
3
4
5
6
7
8
9
10
11
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());
    }
}

最好的解决方案是将随机数生成器与base64转换一起使用。

1
2
3
4
5
6
public string GenRandString(int length)
{
  byte[] randBuffer = new byte[length];
  RandomNumberGenerator.Create().GetBytes(randBuffer);
  return System.Convert.ToBase64String(randBuffer).Remove(length);
}


一个LINQ一号衬垫,用于良好测量(假设为private static Random Random)。

1
2
3
4
public static string RandomString(int length)
{
    return new string(Enumerable.Range(0, length).Select(_ => (char)Random.Next('a', 'z')).ToArray());
}

这是因为每一个新的随机实例都是通过这么快的调用生成相同的数字。不要一直创建新实例,只需调用next()并在方法之外声明随机类。


您应该让一个类级随机对象在构造函数中启动一次,并在每次调用时重复使用(这将继续使用相同的伪随机数序列)。无参数构造函数已在内部为生成器植入environment.tickCount。


我添加了使用ranvir解决方案选择长度的选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
        }
    }

我想这也可以接受和简单。

1
Guid.NewGuid().ToString()


下面是我对当前接受的答案的修改,我认为它更快、更短:

1
2
3
4
5
6
7
8
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();
}

注意,我没有使用所有的乘法,Math.floor()Convert等。

编辑:可以将random.Next(0x41, 0x5A)更改为任何Unicode字符范围。


我的RandomString()方法生成随机字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
}

这是一篇博客文章,它为生成随机单词、句子和段落提供了一个更强大的类。


如果要为强密码生成一个数字和字符字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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();
        }


将"pushcode"和使用种子的答案组合为随机生成器。我需要它来创建一系列伪可读的"单词"。

1
2
3
4
5
private int RandomNumber(int min, int max, int seed=0)
{
    Random random = new Random((int)DateTime.Now.Ticks + seed);
    return random.Next(min, max);
}


对于随机字符串生成器:

1
2
3
4
5
6
7
8
9
10
11
#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

我创建了这个方法。

它很好用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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;
    }


这里还有一个基于guid的想法。我在Visual Studio性能测试中使用它来生成只包含字母数字字符的随机字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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;
    }
}

您还需要:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
    }
}

而这:

1
2
3
4
5
6
7
8
9
10
11
12
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);
    }
}

实际上,一个好的解决方案是为随机数生成器提供一个静态方法,它是线程安全的,不使用锁。

这样,多个同时访问您的Web应用程序的用户就不会得到相同的随机字符串。

这里有3个例子:http://blogs.msdn.com/b/pfxteam/archive/2009/02/19/9434171.aspx

我用最后一个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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();
    }
}

然后你可以适当地消除

1
Random random = new Random();

只需调用randomgen3.next(),而您的方法可以保持静态。


在我的情况下,密码必须包含:

  • 至少一个小写。
  • 至少一个大写。
  • 至少一位小数。
  • 至少一个特殊字符。

这是我的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
    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;
    }

如果您可以访问与Intel Secure Key兼容的CPU,则可以使用以下库生成真正的随机数和字符串:https://github.com/jebtek/rdrand和https://www.rdrand.com/

从这里下载最新版本,包括jebtek.rdrand并为其添加一个using语句。那么,你需要做的就是:

1
2
bool isAvailable = RdRandom.GeneratorAvailable(); //Check to see if this is a compatible CPU
string key = RdRandom.GenerateKey(10); //Generate 10 random characters

此外,您还可以获得以下附加功能:

1
2
3
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

如果没有兼容的CPU来执行代码,只需使用rdrand.com上的restful服务。有了项目中包含的RDRandom包装库,您只需要这样做(注册时可以获得1000个免费调用):

1
string ret = Randomizer.GenerateKey(<length>,"<key>");

您还可以生成随机字节数组和无符号整数,如下所示:

1
2
uint ret = Randomizer.GenerateUInt("<key>");
byte[] ret = Randomizer.GenerateBytes(<length>,"<key>");

还有,另一个版本:我在测试中使用这种方法生成随机伪股票符号:

1
2
3
4
Random rand = new Random();
Func<char> randChar = () => (char)rand.Next(65, 91); // upper case ascii codes
Func<int,string> randStr = null;
    randStr = (x) => (x>0) ? randStr(--x)+randChar() :""; // recursive

用途:

1
2
string str4 = randStr(4);// generates a random 4 char string
string strx = randStr(rand.next(1,5)); // random string between 1-4 chars in length

您可以重新定义randchar函数,以便按位置而非ASCII代码与"允许"的字符数组一起使用:

1
2
char[] allowedchars = {'A','B','C','1','2','3'};
Func<char> randChar = () => allowedchars[rand.Next(0, allowedchars.Length-1)];

这是我的解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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;

我发现这更有用,因为它是一个扩展,它允许您选择代码的源代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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 };

希望这有帮助。


另一个样本(在VS2013中测试):

1
2
3
4
5
6
7
8
9
10
    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);

由本人实施。


您好
您可以使用mmlib.rapidprototyping nuget包中的wordGenerator或loremipsumGenerator。

1
2
3
4
5
6
7
8
using MMLib.RapidPrototyping.Generators;
public void WordGeneratorExample()
{
   WordGenerator generator = new WordGenerator();
   var randomWord = generator.Next();

   Console.WriteLine(randomWord);
}

NuGET站点
codeplex项目站点