How can I generate random alphanumeric strings? [c

2018-12-31 07:14发布

How can I generate random 8 character alphanumeric strings in C#?

标签: c# .net random
30条回答
几人难应
2楼-- · 2018-12-31 07:27

Here is a mechanism to generate a random alpha-numeric string (I use this to generate passwords and test data) without defining the alphabet and numbers,

CleanupBase64 will remove necessary parts in the string and keep adding random alpha-numeric letters recursively.

        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);
        }
查看更多
ら面具成の殇う
3楼-- · 2018-12-31 07:30

The simplest:

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

You can get better performance if you hard code the char array and rely on System.Random:

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

If ever you worry the English alphabets can change sometime around and you might lose business, then you can avoid hard coding, but should perform slightly worse (comparable to Path.GetRandomFileName approach)

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

The last two approaches looks better if you can make them an extension method on System.Random instance.

查看更多
路过你的时光
4楼-- · 2018-12-31 07:30

The code written by Eric J. is quite sloppy (it is quite clear that it is from 6 years ago... he probably wouldn't write that code today), and there are even some problems.

Unlike some of the alternatives presented, this one is cryptographically sound.

Untrue... There is a bias in the password (as written in a comment), bcdefgh are a little more probable than the others (the a isn't because by the GetNonZeroBytes it isn't generating bytes with a value of zero, so the bias for the a is balanced by it), so it isn't really cryptographically sound.

This should correct all the problems.

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);
    }
}
查看更多
一个人的天荒地老
5楼-- · 2018-12-31 07:31

Solution 1 - largest 'range' with most flexible length

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

This solution has more range than using a GUID because a GUID has a couple of fixed bits that are always the same and therefore not random, for example the 13 character in hex is always "4" - at least in a version 6 GUID.

This solution also lets you generate a string of any length.

Solution 2 - One line of code - good for up to 22 characters

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

You can't generate strings as long as Solution 1 and the string doesn't have the same range due to fixed bits in GUID's, but in a lot of cases this will do the job.

Solution 3 - Slightly less code

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

Mostly keeping this here for historical purpose. It uses slightly less code, that though comes as the expense of having less range - because it uses hex instead of base64 it takes more characters to represent the same range compared the other solutions.

Which means more chance of collision - testing it with 100,000 iterations of 8 character strings generated one duplicate.

查看更多
泛滥B
6楼-- · 2018-12-31 07:31

Here's an example that I stole from Sam Allen example at Dot Net Perls

If you only need 8 characters, then use Path.GetRandomFileName() in the System.IO namespace. Sam says using the "Path.GetRandomFileName method here is sometimes superior, because it uses RNGCryptoServiceProvider for better randomness. However, it is limited to 11 random characters."

GetRandomFileName always returns a 12 character string with a period at the 9th character. So you'll need to strip the period (since that's not random) and then take 8 characters from the string. Actually, you could just take the first 8 characters and not worry about the period.

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

PS: thanks Sam

查看更多
心情的温度
7楼-- · 2018-12-31 07:33
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;
    }
}
查看更多
登录 后发表回答