随机字符串生成器:Unicode超出范围?

时间:2017-06-08 12:01:49

标签: c# random

我正在尝试在C#中创建一个随机字符串生成器,给定字符串的长度。我的第一次尝试是这样的:

public static string RandomString(int characters)
{
    string s = "";
    for (int i = 0; i < characters; i++)
    {
        s += Convert.ToChar((97 + r.Next(26)));
    }
    return s;
}

但是 k 之前字母的频率非常低,所以我试着通过编写自己的随机函数来改变它:

public static string RandomString(int characters)
{
    string s = "";
    for (int i = 0; i < characters; i++)
    {
        int randomLetter = 0;

        for (int bit = 0; i < 5; bit++)
        {
            if (r.Next(2) == 0)
                continue;
            randomLetter += 1 << bit;

            if (randomLetter + (1 << (bit + 1)) > 26)
                break;
        }
        s += Convert.ToChar(97 + randomLetter);
    }
    return s;
}

但有时randomLetter会大于26,有时候太大了。我找不到这个问题的原因,可以吗?

6 个答案:

答案 0 :(得分:3)

如果您只想要一个简单的随机字符串,这种方法应该更简单:

private static Random random = new Random();

public static string GetRandomString(int length)
{
    var chars = new char[length];
    var possibleLetters = "abcdefghijklmnopqrstuvwxyz";        

    for (int i = 0; i < length; i++)
    {
        chars[i] = possibleLetters[random.Next(0, possibleLetters.Length - 1)];
    }

    return new string(chars);
}

我刚用你的代码对我的控制台进行了测试:

System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
for (int i = 0; i < 1000; i++)
{
   string s = RandomString(10000);
}
sw.Stop();
Console.WriteLine(sw.Elapsed.TotalMilliseconds);
sw.Restart();

for (int i = 0; i < 1000; i++)
{
    string s = GetRandomString(10000);
}

sw.Stop();
Console.WriteLine(sw.Elapsed.TotalMilliseconds);
Console.Read();

结果:

RandomString => 18830,7537
GetRandomString => 321.098

正如您所看到的,您的实现不仅更糟糕,而且执行速度也慢得多。

为了证明好奇心,我用StringBuilder重新创建了我的方法:

private static string GetRandomStringSB(int length)
{
   var stringBuilder = new StringBuilder(length);

   var possibleLetters = "abcdefghijklmnopqrstuvwxyz";

   for (int i = 0; i < length; i++)
   {
       stringBuilder.Append(possibleLetters[r.Next(0, possibleLetters.Length - 1)]);
   }

   return stringBuilder.ToString();
}

毫不奇怪,结果并没有太多推迟:

RandomString (OP) => 13175
GetRandomString (char[]) => 213
GetRandomStringSB (StringBuilder) => 244

答案 1 :(得分:2)

为什么所有这些按位算术?首先,让我们说明问题:

  

我想生成characters长度的随机字符串;该字符串应包含a .. z   应该有均匀分布

实施起来很简单:

// Simplest, but not thread safe
private static Random s_Random = new Random();

// Not thread safe
public static string RandomString(int characters) {
  if (characters < 0)
    throw new ArgumentOutOfRangeException("characters");

  StringBuilder sb = new StringBuilder(characters);

  // I personally, prefer Linq + Concat, but let's preserve the loop
  for (int i = 0; i < characters; ++i) {
    char c = (char)(s_Random.Next('z' - 'a' + 1) + 'a'); // +1 - 'z' should be included

    sb.Append(c);
  }

  return sb.ToString();
}

Linq 版本更短,但可能更少可读

// Not thread safe
public static string RandomString(int characters) {
  if (characters < 0)
    throw new ArgumentOutOfRangeException("characters");

  return string.Concat(Enumerable
    .Range(0, characters)
    .Select(i => (char)(s_Random.Next('z' - 'a' + 1) + 'a')));
}

测试:

Console.Write(RandomString(10));

结果(可能会有所不同):

dcdwwvzhnz

最后,让我们看一下实际的发布&#34; ...但频率 之前 strong> k 非常低 ..&#34;

  int count = 1000; // we examine "count" random string
  int length = 10;  // each of "length" length 

  var distribution = String
    .Concat(Enumerable.Range(1, count).Select(i => RandomString(length)))
    .GroupBy(c => c, (k, s) => new {
      key = k,
      freq = (double)s.Count() / length / count
    })
    .OrderBy(item => item.freq)
    .Select(item => $"{item.key}: {item.freq:F4}")
    .ToArray();

  Console.Write(string.Join(Environment.NewLine, distribution));

结果(可能会有所不同):没有证据这样的倾斜

p: 0.0351
a: 0.0359
r: 0.0360
y: 0.0362
l: 0.0363
z: 0.0364
n: 0.0369
u: 0.0370
h: 0.0371
e: 0.0373
c: 0.0375
v: 0.0376
x: 0.0376
o: 0.0380
q: 0.0380
m: 0.0388
k: 0.0389
d: 0.0391
s: 0.0391
g: 0.0396
w: 0.0401
b: 0.0406
t: 0.0406
f: 0.0422
i: 0.0434
j: 0.0447

答案 2 :(得分:0)

使用这些方法,您可以指定有效字符,或接受所有字符。

    public static string RandomString(int len)
    {
        var array = Enumerable.Range(char.MinValue, char.MaxValue - char.MinValue + 1).Select(x => (char)x).ToArray();
        return RandomString(len, array);
    }

    private static string RandomString(int len, char[] array)
    {
        Random r = new Random();
        StringBuilder sb = new StringBuilder();
        while (sb.Length < len)
            sb.Append(array[r.Next(array.Length-1)]);
        return sb.ToString();
    }

答案 3 :(得分:0)

这是一个简单的函数,可以生成随机字符串

.once()

答案 4 :(得分:0)

如果你想随机。

private static System.Security.Cryptography.RandomNumberGenerator random = System.Security.Cryptography.RandomNumberGenerator.Create();
public static string Random(int characters)
        {
            var data = new byte[characters];
            random.GetBytes(data);
            return data.Select(b=>Convert.ToChar((int)(96 + (Math.Floor((b/(double)byte.MaxValue)*27)) - 1))).Aggregate(new System.Text.StringBuilder(),(a,c) => a.Append(c)).ToString();
        }

请注意,这不是快速而是随机的

答案 5 :(得分:-3)

感谢@Evk我明白了。我最后的方法:

public static string RandomString(int characters)
    {
        string s = "";
        for (int i = 0; i < characters; i++)
        {
            int ascii = 0;

            for (int bit = 0; bit < 5; bit++)
            {
                if (r.Next(2) == 0)
                    continue;
                ascii += 1 << bit;

                if (ascii + (1 << (bit + 1)) > 25)
                    break;
            }
            s += Convert.ToChar(97 + ascii);
        }
        return s;
    }