tags:

views:

2419

answers:

8

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

+28  A: 

I heard LINQ is the new black, so here's my attempt using LINQ:

var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var random = new Random();
var result = new string(
    Enumerable.Repeat(chars, 8)
              .Select(s => s[random.Next(s.Length)])
              .ToArray());
dtb
Unique solution to a common question. I like +1
Spencer Ruport
+1 Linq is definitely the new black :-)
Tim Jarvis
If Linq is the new black, is var the new dim? +1 btw, über elegant.
Paul Sasik
dtb the linq kinq.
Alex
We would need a performance test on this one btw. Maybe on generating 8000 instead of 8 characters.
Alex
@Alex: I've run a few quick tests and it seems to scale pretty much linearly when generating longer strings (so long as there's actually enough memory available). Having said that, Dan Rigby's answer was almost twice as fast as this one in every test.
LukeH
@Luke: Thanks! +1 to you and Dan Rigby.
Alex
@Luke: Thanks for the benchmarking, thats really good information to know! @Alex: Good idea suggesting the benchmark.
Dan Rigby
+2  A: 

This implementation (found via google) looks sound to me:

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

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

Picked that one from a discussion of alternatives here

Eric J.
+22  A: 

Not as elegant as the Linq solution. (-:

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);
Dan Rigby
I think yours is better than Linq
Barbaros Alp
@Barbaros Alp: But it's *soooo* 20th century ;-)
dtb
I know i know :)))
Barbaros Alp
+1. According to Luke, the fastest answer :)
Alex
@Alex: This isn't the absolute fastest answer, but it is the fastest "real" answer (ie, of those that allow control over the characters used and the length of the string).
LukeH
@Alex: Adam Porad's `GetRandomFileName` solution is quicker but doesn't allow any control of the characters used and the max possible length is 11 chars. Douglas's `Guid` solution is lightning-fast but the characters are restricted to A-F0-9 and the max possible length is 32 chars.
LukeH
You could get more than 11 chars using the GetRandomFileName solution, by getting multiple strings from the GetRandomeFileName method and concatonating. You're right about limited character set -- only lowercase a-z and numbers. Not sure how that would compare performance-wise if you're trying to generate a long random string.
Adam Porad
Nice answer, but what happened to "wxyz" ? :)
Moe Sisko
@Adam: Yes, you could concat the result of multiple calls to `GetRandomFileName` but then (a) you'd lose your performance advantage, and (b) your code would become more complicated.
LukeH
@Moe Oops! Fixed it.
Dan Rigby
+2  A: 

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

Adam Porad
A bit too clever for my tastes. I prefer the more straightforward approach.
JohnFx
+4  A: 

Why not just use a Guid?

Guid.NewGuid().ToString().Replace("-", string.Empty).Substring(0, 8);

Just tested with 100,000 iterations, generated only one duplicate.

Edit: Technically you do not need the call to .Replace. The dash comes after the first 8 characters in a Guid. I’m used to having to generate 16 char random numbers for a project I work on. Should be:

Guid.NewGuid().ToString().Substring(0, 8);
Douglas
You actually generated a duplicate? Surprising at 5,316,911,983,139,663,491,615,228,241,121,400,000 possible combinations of GUIDs.
Alex
(The chance for that happening is 1.8807909613156600127499784595556e-27, or virtually 0)
Alex
Yip. I was supprised too. Just re-ran it and no duplicate this time.
Douglas
@Alex: He's shortening the GUID to 8 characters, so the probability of collisions is much higher than that of GUIDs.
dtb
Nobody can appreciate this other than nerds :) Yes you are absolutely right, the 8 char limit makes a difference.
Alex
Guid.NewGuid().ToString("n") will keep the dashes out, no Replace() call needed. But it should be mentioned, GUIDs are only 0-9 and A-F. The number of combinations is "good enough," but nowhere close to what a *true* alphanumeric random string permits. The chances of collision are 1:4,294,967,296 -- the same as a random 32-bit integer.
richardtallent
how about allocating a BStr and writing the Guid Inside it?(the only problem is with the Guid version(4))?that will make you Unicode.
Behrooz
A: 

Horrible, I know, but I just couldn't help myself:


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

james
A: 
  1. If you don't need a cryptographically random generator
  2. If you know the length of the output, you don't need a StringBuilder, and when using ToCharArray, this creates and fills the array (you don't need to create an empty array first)
  3. You should use NextBytes, rather than getting one at a time for performance
  4. Technically you could pin the byte array for faster access.. it's usually worth it when your iterating more than 6-8 times over a byte array.
  5. Define your character set and Random gen object once.
  6. My example has a 62 char set and 32 char output
  7. Clearly, you can adjust this example, to accept the string length as a param.

    private static char[] charSet =
      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
    
    
    private static Random rGen = new Random();
    public string GenerateRandomString()
    {
      byte[] rBytes = new byte[32];
      rGen.NextBytes(rBytes);
      char[] rName = new char[32];
      for (int i = 0; i < 32; i++)
        rName[i] = charSet[rBytes[i] % 62];
      return rName.ToString();
    }
    
Merari Schroeder
A: 

If your values are not completely random, but in fact may depend on something - you may compute an md5 or sha1 hash of that 'somwthing' and then truncate it to whatever length you want.

Also you may generate and truncate a guid.

Mr.Cat