どうすればランダムな英数字の文字列を生成できますか?


968

C#でランダムな8文字の英数字の文字列を生成するにはどうすればよいですか?


2
文字セットに制限がある場合、どのような制限がありますか?英語の文字と0-9だけですか?大文字小文字混合ですか?
エリックJ.


9
Randomクラスに基づくメソッドを使用してパスワードを生成しないでください。のシードはRandomエントロピーが非常に低いため、実際には安全ではありません。パスワードには暗号PRNGを使用します。
CodesInChaos

2
この質問に言語のローカリゼーションを含めるとよいでしょう。特に、あなたのGUIが中国人やブルガリア語に対応する必要がある場合は!
Peter Jamsmenson、2015

15
これだけ多くの賛成票とこの多くの質の高い回答があるものは、クローズ済みとしてマークするに値しません。再開することを投票します。
John Coleman

回答:


1686

私はLINQが新しい黒だと聞いたので、LINQを使用した私の試みを次に示します。

private static Random random = new Random();
public static string RandomString(int length)
{
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    return new string(Enumerable.Repeat(chars, length)
      .Select(s => s[random.Next(s.Length)]).ToArray());
}

(注:Randomクラスを使用すると、パスワードやトークンの作成など、セキュリティに関連するあらゆるものには不適切になります。RNGCryptoServiceProvider強力な乱数ジェネレータが必要な場合は、クラスを使用してください。)


24
@アレックス:私はいくつかの簡単なテストを実行しましたが、長い文字列を生成するとき(実際に十分なメモリが利用可能である限り)はかなり直線的にスケーリングしているようです。そうは言っても、Dan Rigbyの回答は、すべてのテストでこの回答のほぼ2倍の速さでした。
LukeH 2009

6
上手。linqを使用し、お粗末なコードナラティブがあることが基準である場合、それは間違いなく蜂の膝です。コードの説明と実際の実行パスはどちらもかなり非効率的で間接的です。誤解しないでください。私は巨大なコードヒップスター(私はpythonが大好きです)ですが、これはかなりゴールドマシンのルーブです。
eremzeit 2011

5
これは技術的に質問に答えますが、出力は非常に誤解を招きます。8つのランダムな文字を生成すると、非常に多くの結果が得られるように聞こえますが、これはせいぜい20億の異なる結果を生成します。そして実際にはさらに少ない。また、これをセキュリティ関連のものに使用しないように、BIG FAT警告を追加する必要があります。
CodesInChaos

41
@xaisoft:小文字は読者のための練習問題として残されています。
dtb 2013

15
次の行は、特定の行よりもメモリ(したがって時間)効率が高いreturn new string(Enumerable.Range(1, length).Select(_ => chars[random.Next(chars.Length)]).ToArray());
Tyson Williams

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

Linqソリューションほどエレガントではありません。

(注:Randomクラスを使用すると、パスワードやトークンの作成など、セキュリティに関連するあらゆるものには不適切になります。RNGCryptoServiceProvider強力な乱数ジェネレータが必要な場合は、クラスを使用してください。)


4
@Alex:これは絶対的な最速の回答ではありませんが、最速の「実際の」回答です(つまり、使用される文字と文字列の長さを制御できる回答の中で)。
LukeH 2009

2
@Alex:Adam PoradのGetRandomFileNameソリューションはより高速ですが、使用する文字を制御できず、最大長は11文字です。ダグラスのGuidソリューションは超高速ですが、文字はA-F0-9に制限されており、可能な最大長は32文字です。
LukeH 2009

1
@Adam:はい、複数の呼び出しの結果を連結できますがGetRandomFileName、(a)パフォーマンスの利点が失われ、(b)コードがより複雑になります。
LukeH 2009

2
@xaisoftは、ループの外でRandom()オブジェクトのインスタンスを作成します。短い間隔で多くのRandom()のインスタンスを作成した場合、.Next()への呼び出しは、Random()が時間ベースのシードを使用するのと同じ値を返します。
Dan Rigby 2013

2
@xaisoftパスワードなど、セキュリティ上重要なものにはこの回答を使用しないでください。System.Randomセキュリティには適していません。
CodesInChaos 2013年

333

コメントに基づいて更新されました。元の実装では、時間の約1.95%と残りの文字数の約1.56%が生成されました。更新では、すべての文字が最大で1.61%生成されます。

フレームワークのサポート-.NET Core 3(および.NET Standard 2.1以上をサポートする将来のプラットフォーム)は、暗号的に適切なメソッドRandomNumberGenerator.GetInt32()を提供して、目的の範囲内でランダムな整数を生成します。

提示されたいくつかの代替案とは異なり、これは暗号的に健全です。

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

namespace UniqueKey
{
    public class KeyGenerator
    {
        internal static readonly char[] chars =
            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray(); 

        public static string GetUniqueKey(int size)
        {            
            byte[] data = new byte[4*size];
            using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
            {
                crypto.GetBytes(data);
            }
            StringBuilder result = new StringBuilder(size);
            for (int i = 0; i < size; i++)
            {
                var rnd = BitConverter.ToUInt32(data, i * 4);
                var idx = rnd % chars.Length;

                result.Append(chars[idx]);
            }

            return result.ToString();
        }

        public static string GetUniqueKeyOriginal_BIASED(int size)
        {
            char[] chars =
                "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
            byte[] data = new byte[size];
            using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
            {
                crypto.GetBytes(data);
            }
            StringBuilder result = new StringBuilder(size);
            foreach (byte b in data)
            {
                result.Append(chars[b % (chars.Length)]);
            }
            return result.ToString();
        }
    }
}

ここでの代替案の議論に基づき、以下のコメントに基づいて更新/変更されました。

以下は、古い出力と更新された出力での文字の分布を示す小さなテストハーネスです。ランダム性分析の詳細については、random.orgをご覧ください。

using System;
using System.Collections.Generic;
using System.Linq;
using UniqueKey;

namespace CryptoRNGDemo
{
    class Program
    {

        const int REPETITIONS = 1000000;
        const int KEY_SIZE = 32;

        static void Main(string[] args)
        {
            Console.WriteLine("Original BIASED implementation");
            PerformTest(REPETITIONS, KEY_SIZE, KeyGenerator.GetUniqueKeyOriginal_BIASED);

            Console.WriteLine("Updated implementation");
            PerformTest(REPETITIONS, KEY_SIZE, KeyGenerator.GetUniqueKey);
            Console.ReadKey();
        }

        static void PerformTest(int repetitions, int keySize, Func<int, string> generator)
        {
            Dictionary<char, int> counts = new Dictionary<char, int>();
            foreach (var ch in UniqueKey.KeyGenerator.chars) counts.Add(ch, 0);

            for (int i = 0; i < REPETITIONS; i++)
            {
                var key = generator(KEY_SIZE); 
                foreach (var ch in key) counts[ch]++;
            }

            int totalChars = counts.Values.Sum();
            foreach (var ch in UniqueKey.KeyGenerator.chars)
            {
                Console.WriteLine($"{ch}: {(100.0 * counts[ch] / totalChars).ToString("#.000")}%");
            }
        }
    }
}

11
これは私にとって正しいアプローチのように見えます-ランダムなパスワード、ソルト、エントロピーなどは、速度を最適化し、再現可能な数列を生成するRandom()を使用して生成しないでください。一方、RNGCryptoServiceProvider.GetNonZeroBytes()は、再現できない数値のワイルドシーケンスを生成します。
mindplay.dk 2011

25
文字は少し偏っています(255%62!= 0)。このマイナーな欠陥にもかかわらず、これは断然最高のソリューションです。
CodesInChaos

13
暗号強度、不偏ランダム性が必要な場合、これは適切ではないことに注意してください。(そして、あなたは、なぜ、使用したくない場合はRNGCSP最初の場所では?)へのインデックスにMODを使用charsしない限り、あなたは出力をバイアスがかかりますことをアレイ手段chars.Length256の除数であることを起こる
LukeH

15
バイアスを大幅に減らす1つの可能性は、4*maxSizeランダムなバイトを要求してからを使用すること(UInt32)(BitConverter.ToInt32(data,4*i)% chars.Lengthです。のGetBytes代わりにも使用しますGetNonZeroBytes。そして最後に、への最初の呼び出しを削除できますGetNonZeroBytes。あなたはその結果を使用していません。
CodesInChaos

14
面白い事実:AZ az 0-9は62文字です。256%62!= 0であるため、人々は文字バイアスを指摘しています。YouTubeのビデオIDはAZ az 0-9であり、「-」と「_」は64の可能な文字を生成し、256に等分します。一致?私はそうは思いません!:)
qJake 2016

200

ソリューション1-最も柔軟な長さの最大の「範囲」

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

このソリューションは、GUIDを使用するよりも範囲が広くなります。GUIDには常に同じでランダムではない2つの固定ビットがあるためです。たとえば、16進数の13文字は常に「4」です-少なくともバージョン6 GUIDでは。

このソリューションでは、任意の長さの文字列を生成することもできます。

ソリューション2-1行のコード-最大22文字まで

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

GUIDのビットが固定されているため、ソリューション1と文字列の範囲が同じでない限り、文字列を生成できませんが、多くの場合、これでうまくいきます。

ソリューション3-少し少ないコード

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

主に歴史的な目的のためにこれをここに保持します。使用するコードが少し少なくなりますが、範囲が狭くなるという犠牲になります。base64の代わりに16進数を使用するため、他のソリューションと比較して、同じ範囲を表すためにより多くの文字が必要になります。

つまり、衝突の可能性が高くなります。8つの文字列を100,000回繰り返してテストすると、1つの複製が生成されます。


22
実際に複製を生成しましたか?驚くべきことに、5,316,911,983,139,663,491,615,228,241,121,400,000の可能なGUIDの組み合わせがあります。
アレックス

73
@アレックス:彼はGUIDを8文字に短縮しているため、衝突の確率はGUIDの確率よりもはるかに高くなります。
dtb 2009

23
オタク以外の誰もこれを認めることができません:)はい、あなたは絶対に正しいです、8文字の制限は違いを生みます。
アレックス

31
Guid.NewGuid()。ToString( "n")はダッシュを保持します。Replace()呼び出しは必要ありません。ただし、GUIDは0〜9とAFのみです。組み合わせの数は「十分に良い」ですが、真の英数字のランダム文字列が許可するものに近いところはありません。衝突の可能性は1:4,294,967,296-ランダムな32ビット整数と同じです。
richardtallent 2009

32
1)GUIDはランダムではなく一意になるように設計されています。Windowsの現在のバージョンでは、実際にランダムなV4 GUIDが生成されますが、これは保証されていません。たとえば、古いバージョンのウィンドウではV1 GUIDが使用されていたため、失敗する可能性がありました。2)16進文字を使用すると、ランダム文字列の品質が大幅に低下します。47〜32ビット。3)人々は、個々のペアに与えるため、衝突確率を過小評価しています。100kの32ビット値を生成する場合、おそらくそれらの間で1つの衝突があります。誕生日の問題を参照してください。
CodesInChaos

72

これは私がDot Net PerlsでSam Allenの例から盗んだ例です

8文字のみ必要な場合は、System.IO名前空間でPath.GetRandomFileName()を使用します。サムは、「Path.GetRandomFileNameメソッドを使用すると、ランダム性を高めるためにRNGCryptoServiceProviderを使用するため、優れている場合があります。ただし、ランダムな文字は11文字に制限されています。」

GetRandomFileNameは常に、9番目の文字にピリオドを含む12文字の文字列を返します。したがって、(ランダムではないため)ピリオドを取り除き、文字列から8文字を取得する必要があります。実際には、最初の8文字だけを使用して、ピリオドを気にする必要はありません。

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

PS:サムに感謝


27
これはうまくいきます。私は100,000回の反復を実行しましたが、重複する名前はありませんでした。しかし、私下品な単語(英語)をいくつか見つけました。リストの最初の1つにF ***が含まれている場合を除いて、これについては考えもしなかったでしょう。これをユーザーに表示するために使用する場合は、注意が必要です。
techturtle 2012年

3
@techturtle警告をありがとう。アルファベットのすべての文字を使用するランダムな文字列生成を伴う下品な単語のリスクがあると思います。
Adam Porad

素晴らしくシンプルですが、長い文字列には適していません...この良いトリックに投票してください
Maher Abuthraa 14

このメソッドは、小文字の英数字文字列のみを返すようです。
ジェイブロ2014年

2
時々下品な言葉がありますが、これを十分長く実行し続けると、最終的にシェイクスピアになります。(宇宙のほんのわずかな寿命。)
Slothario 2018

38

私のコードの主な目標は次のとおりです。

  1. 文字列の分布はほぼ均一です(小さい限り、小さな偏差は気にしないでください)。
  2. 引数セットごとに数十億以上の文字列を出力します。PRNGが20億(31ビットのエントロピー)の異なる値しか生成しない場合、8文字の文字列(47ビットのエントロピー)を生成しても意味がありません。
  3. パスワードやその他のセキュリティトークンに使用することを期待しているので、安全です。

最初のプロパティは、アルファベットサイズを法とする64ビット値を取ることで実現されます。小さなアルファベット(質問の62文字など)の場合、これは無視できるバイアスにつながります。2番目と3番目のプロパティは、のRNGCryptoServiceProvider代わりにを使用して実現されSystem.Randomます。

using System;
using System.Security.Cryptography;

public static string GetRandomAlphanumericString(int length)
{
    const string alphanumericCharacters =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
        "abcdefghijklmnopqrstuvwxyz" +
        "0123456789";
    return GetRandomString(length, alphanumericCharacters);
}

public static string GetRandomString(int length, IEnumerable<char> characterSet)
{
    if (length < 0)
        throw new ArgumentException("length must not be negative", "length");
    if (length > int.MaxValue / 8) // 250 million chars ought to be enough for anybody
        throw new ArgumentException("length is too big", "length");
    if (characterSet == null)
        throw new ArgumentNullException("characterSet");
    var characterArray = characterSet.Distinct().ToArray();
    if (characterArray.Length == 0)
        throw new ArgumentException("characterSet must not be empty", "characterSet");

    var bytes = new byte[length * 8];
    var result = new char[length];
    using (var cryptoProvider = new RNGCryptoServiceProvider())
    {
        cryptoProvider.GetBytes(bytes);
    }
    for (int i = 0; i < length; i++)
    {
        ulong value = BitConverter.ToUInt64(bytes, i * 8);
        result[i] = characterArray[value % (uint)characterArray.Length];
    }
    return new string(result);
}

1
64 x ZおよびMath.Pow(2、Y)との交差はありません。したがって、数値を大きくするとバイアスが減少しますが、それが排除されるわけではありません。回答を以下に更新しました。私のアプローチは、ランダムな入力を破棄して別の値に置き換えることでした。
トッド

@Todd私はそれがバイアスを排除しないことを知っていますが、私は実際に無関係なバイアスを排除するよりもこのソリューションのシンプルさを選びました。
CodesInChaos 2016

ほとんどの場合、それはおそらく実質的に無関係であることに同意します。しかし、私は私のものをランダムと同じくらい速くそしてあなたのものよりも少し安全になるように更新しました。すべてを共有するためのすべてのオープンソース。はい、私はこれにあまりにも多くの時間を浪費しました...
Todd

RNGプロバイダーを使用している場合、理論的にバイアスを回避する方法はありますか?わかりません...トッドが(バイアスゾーンにいるときに)追加の乱数を生成する方法を意味している場合、それは誤った仮定である可能性があります。RNGは、平均して生成されたすべての値のほぼ線形の分布を持っています。ただし、生成されたバイト間にローカルな相関関係がないことを意味するものではありません。そのため、バイアスゾーン専用の追加バイトでも、バイアスを与えることができますが、理由は異なります。ほとんどの場合、このバイアスは非常に小さくなります。しかし、この場合、生成された総バイト数を増やす方が簡単です。
マキシム

1
@Maxim拒否を使用してバイアスを完全に排除できます(基礎となるジェネレーターが完全にランダムであると想定)。引き換えに、コードは任意に長く実行される可能性があります(指数関数的に小さな確率で)。
CodesInChaos 2017

32

もっとも単純な:

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

char配列をハードコーディングして、以下に依存する場合、パフォーマンスが向上しますSystem.Random

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

英語のアルファベットがいつか変わってビジネスを失う可能性があることを心配するなら、ハードコーディングを避けることができますが、わずかに悪いパフォーマンスになるはずです(Path.GetRandomFileNameアプローチに匹敵します)。

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

最後の2つのアプローチは、System.Randomインスタンスの拡張メソッドにすることができれば、より良く見えます。


1
chars.Select出力サイズが最大でもアルファベットサイズであることに依存しているため、使用は非常に醜い方法です。
CodesInChaos

@CodesInChaos理解できるかわかりません。あなたは'a'.To('z')アプローチで意味しますか?
nawfal 14年

1
1)chars.Select().Take(n) `はchars.Count >= n。実際に使用しないシーケンスを選択することは、特に暗黙的な長さの制約がある場合、少し直感的ではありません。Enumerable.Rangeまたはを使用しますEnumerable.Repeat。2)「終了文字は開始文字よりも小さくなければなりません」というエラーメッセージは、を巡る/欠落する間違った方法notです。
CodesInChaos 2014年

@CodesInChaosですが、私の場合chars.Countは方法> nです。また、私は直感的でない部分を取得しません。それはすべての使用をTake直感的にしませんか?信じられない。タイプミスを指摘していただきありがとうございます。
nawfal 2014年

4
これは、CodeSODの記事としてtheDailyWTF.comで紹介されています。

22

このスレッドのさまざまな回答のパフォーマンス比較の一部:

メソッドとセットアップ

// what's available
public static string possibleChars = "abcdefghijklmnopqrstuvwxyz";
// optimized (?) what's available
public static char[] possibleCharsArray = possibleChars.ToCharArray();
// optimized (precalculated) count
public static int possibleCharsAvailable = possibleChars.Length;
// shared randomization thingy
public static Random random = new Random();


// http://stackoverflow.com/a/1344242/1037948
public string LinqIsTheNewBlack(int num) {
    return new string(
    Enumerable.Repeat(possibleCharsArray, num)
              .Select(s => s[random.Next(s.Length)])
              .ToArray());
}

// http://stackoverflow.com/a/1344258/1037948
public string ForLoop(int num) {
    var result = new char[num];
    while(num-- > 0) {
        result[num] = possibleCharsArray[random.Next(possibleCharsAvailable)];
    }
    return new string(result);
}

public string ForLoopNonOptimized(int num) {
    var result = new char[num];
    while(num-- > 0) {
        result[num] = possibleChars[random.Next(possibleChars.Length)];
    }
    return new string(result);
}

public string Repeat(int num) {
    return new string(new char[num].Select(o => possibleCharsArray[random.Next(possibleCharsAvailable)]).ToArray());
}

// http://stackoverflow.com/a/1518495/1037948
public string GenerateRandomString(int num) {
  var rBytes = new byte[num];
  random.NextBytes(rBytes);
  var rName = new char[num];
  while(num-- > 0)
    rName[num] = possibleCharsArray[rBytes[num] % possibleCharsAvailable];
  return new string(rName);
}

//SecureFastRandom - or SolidSwiftRandom
static string GenerateRandomString(int Length) //Configurable output string length
{
    byte[] rBytes = new byte[Length]; 
    char[] rName = new char[Length];
    SolidSwiftRandom.GetNextBytesWithMax(rBytes, biasZone);
    for (var i = 0; i < Length; i++)
    {
        rName[i] = charSet[rBytes[i] % charSet.Length];
    }
    return new string(rName);
}

結果

LinqPadでテスト済み。文字列サイズが10の場合、以下を生成します。

  • Linq = chdgmevhcyから[10]
  • ループ= gtnoaryhxr [10]から
  • Select = rsndbztyby [10]から
  • GenerateRandomString = owyefjjakj [10]から
  • SecureFastRandom = VzougLYHYPから[10]
  • SecureFastRandom-NoCacheから= oVQXNGmO1S [10]

そして、パフォーマンスの数値はわずかに変化する傾向があり、非常にまれNonOptimizedに実際には高速であり、場合によっては、リードしている人ForLoopGenerateRandomString切り替えます。

  • LinqIsTheNewBlack(10000x)= 96762ティック経過(9.6762 ms)
  • ForLoop(10000x)= 28970ティック経過(2.897ミリ秒)
  • ForLoopNonOptimized(10000x)= 33336ティックの経過(3.3336 ms)
  • 繰り返し(10000x)= 78547ティック経過(7.8547ミリ秒)
  • GenerateRandomString(10000x)= 27416ティックの経過(2.7416ミリ秒)
  • SecureFastRandom(10000x)= 13176ティック経過(5ms)最低[別のマシン]
  • SecureFastRandom-NoCache(10000x)= 39541ティック経過(17​​ms)最低[別のマシン]

3
どの人がだまされたのかを知るのは興味深いでしょう。
レベッカ

@Junto-のような結果になる重複の原因を特定するには、次のようvar many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());に置き換えEachRandomizingMethodます...各メソッド
drzaus

19

1行のコードでMembership.GeneratePassword()うまくいきます:)

これは同じもののデモです。


1
Microsoftがリンクを移動したようです。別のコードサンプルは msdn.microsoft.com/en-us/library/ms152017またはaspnet.4guysfromrolla.com/demos/GeneratePassword.aspxまたはdeveloper.xamarin.com/api/member/…にあります。
Pooran

私はそれを考えましたが、2番目の引数がMINIMUM非英字であるため、非英字を取り除くことができませんでした
ozzy432836

13

エリックJによって書かれたコードはかなりずさんで(6年前からのものであることは明らかです...彼はおそらくそのコードを今日は書かないでしょう)、さらにいくつかの問題があります。

提示されたいくつかの代替案とは異なり、これは暗号的に健全です。

Untrue ...(コメントに書かれているように)パスワードにはバイアスがあります。bcdefgh他のものよりも少し確率が高いです(それがa原因GetNonZeroBytesでゼロの値を持つバイトを生成していないので、バイアスは以下のためにa)、それによってバランスされているので、それは本当に、暗号音ではありません。

これですべての問題が修正されます。

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

7

また、カスタム文字列ランダムを使用しますが、文字列のヘルパーとして実装しているため、ある程度の柔軟性が得られます...

public static string Random(this string chars, int length = 8)
{
    var randomString = new StringBuilder();
    var random = new Random();

    for (int i = 0; i < length; i++)
        randomString.Append(chars[random.Next(chars.Length)]);

    return randomString.ToString();
}

使用法

var random = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".Random();

または

var random = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".Random(16);

7

私の簡単な1行のコードでうまくいきます:)

string  random = string.Join("", Guid.NewGuid().ToString("n").Take(8).Select(o => o));

Response.Write(random.ToUpper());
Response.Write(random.ToLower());

任意の長さの文字列についてこれを拡張するには

    public static string RandomString(int length)
    {
        //length = length < 0 ? length * -1 : length;
        var str = "";

        do 
        {
            str += Guid.NewGuid().ToString().Replace("-", "");
        }

        while (length > str.Length);

        return str.Substring(0, length);
    }

私はguidメソッドも好きです-本当に軽く感じます
ozzy432836

6

別のオプションは、Linqを使用してランダムな文字を文字列ビルダーに集約することです。

var chars = "abcdefghijklmnopqrstuvwxyz123456789".ToArray();
string pw = Enumerable.Range(0, passwordLength)
                      .Aggregate(
                          new StringBuilder(),
                          (sb, n) => sb.Append((chars[random.Next(chars.Length)])),
                          sb => sb.ToString());

6

質問:Enumerable.Range入力する代わりにを使用して時間を無駄にする必要があるのはなぜ"ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789"ですか?

using System;
using System.Collections.Generic;
using System.Linq;

public class Test
{
    public static void Main()
    {
        var randomCharacters = GetRandomCharacters(8, true);
        Console.WriteLine(new string(randomCharacters.ToArray()));
    }

    private static List<char> getAvailableRandomCharacters(bool includeLowerCase)
    {
        var integers = Enumerable.Empty<int>();
        integers = integers.Concat(Enumerable.Range('A', 26));
        integers = integers.Concat(Enumerable.Range('0', 10));

        if ( includeLowerCase )
            integers = integers.Concat(Enumerable.Range('a', 26));

        return integers.Select(i => (char)i).ToList();
    }

    public static IEnumerable<char> GetRandomCharacters(int count, bool includeLowerCase)
    {
        var characters = getAvailableRandomCharacters(includeLowerCase);
        var random = new Random();
        var result = Enumerable.Range(0, count)
            .Select(_ => characters[random.Next(characters.Count)]);

        return result;
    }
}

回答:魔法の紐は悪いです。I上部の文字列に「」がないことに誰かが気づきましたか?私の母は、まさにこの理由で魔法のひもを使用しないように私に教えました...

nb 1:@dtbのような他の多くの人が言ったように、System.Random暗号化セキュリティが必要な場合は使用しないでください...

nb 2:この回答は、最も効率的または最も短いわけではありませんが、回答と質問を分離するためのスペースが必要でした。私の答えの目的は、派手で革新的な答えを提供することよりも、魔法のひもに対して警告することです。


I?」がないことを気にするのはなぜですか。
クリスティン

1
英数字(大文字と小文字を区別しない)は[A-Z0-9]です。偶然にも、ランダムな文字列[A-HJ-Z0-9]が結果をカバーするだけで、許容範囲全体をカバーしていない場合、これは問題になる可能性があります。
Wai Ha Lee

それはどのように問題がありますか?含まれていませんI。キャラクターが1つ少ないため、クラックが発生しやすくなりますか?36の範囲内に35文字を含むクラック可能なパスワードの統計情報とは何ですか。私は、コードに余分なゴミをすべて含めるよりも、リスクを冒したい、または文字範囲を証明したほうがいいと思います。しかし、それは私です。つまり、お尻の穴ではないということです。時々、プログラマーは超複雑になるために超複雑ルートに行く傾向があると思います。
クリスティン

1
それはユースケースに深く関わっています。それは、次のような文字を除外するために非常に一般的だIOしてそれらを混乱人間を避けるために、ランダムな文字列のこれらのタイプからを1して0。人間が読み取れる文字列を使用する必要がない場合でも、誰かが入力する必要がある可能性がある場合は、実際にそれらの文字を削除するのが賢明です。
クリスプラット

5

DTBのソリューションのややクリーンなバージョン。

    var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    var random = new Random();
    var list = Enumerable.Repeat(0, 8).Select(x=>chars[random.Next(chars.Length)]);
    return string.Join("", list);

スタイルの設定は異なる場合があります。


これは、受け入れられた回答よりもはるかに優れて効率的です。
2016年

5
 public static string RandomString(int length)
    {
        const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        var random = new Random();
        return new string(Enumerable.Repeat(chars, length).Select(s => s[random.Next(s.Length)]).ToArray());
    }

5

他の回答を確認し、CodeInChaosのコメントを検討した後、CodeInChaosはまだ偏っています(ただし少ない)回答で、最終的な最終的なカットアンドペーストソリューションが必要だと思いました。だから私の答えを更新しながら、私はすべてに行くことにしました。

このコードの最新バージョンについては、Bitbucketの新しいHgリポジトリ(https://bitbucket.org/merarischroeder/secureswiftrandom)にアクセスしてください。:私は、あなたがコピーしてからコードを貼り付けをお勧めしますhttps://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwiftRandom.cs?at=default&fileviewer=file-view-default(必ずクリックします簡単にコピーして最新バージョンを使用できるようにするための[Raw]ボタン。このリンクは、最新ではなく特定のバージョンのコードに移動すると思います)。

更新されたメモ:

  1. 他のいくつかの回答に関連して-出力の長さがわかっている場合、StringBuilderは必要ありません。これにより、ToCharArrayを使用すると、配列が作成および入力されます(最初に空の配列を作成する必要はありません)。
  2. 他のいくつかの回答に関連して-パフォーマンスのために一度に1つずつ取得するのではなく、NextBytesを使用する必要があります
  3. 技術的には、バイト配列を固定してアクセスを高速化することができます。通常、バイト配列に対して6〜8回以上反復する場合は、その価値があります。(ここでは行いません)
  4. 最高のランダム性のためRNGCryptoServiceProviderの使用
  5. ランダムデータの1MBバッファキャッシュの使用-ベンチマークは、キャッシュされたシングルバイトアクセス速度が約1000倍高速であることを示しています -キャッシュされていない場合、1msで9ms対989msかかります。
  6. 新しいクラス内のバイアスゾーンの拒否を最適化しました

質問の解決策を終了:

static char[] charSet =  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
static int byteSize = 256; //Labelling convenience
static int biasZone = byteSize - (byteSize % charSet.Length);
public string GenerateRandomString(int Length) //Configurable output string length
{
    byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
    char[] rName = new char[Length];
    SecureFastRandom.GetNextBytesMax(rBytes, biasZone);
    for (var i = 0; i < Length; i++)
    {
        rName[i] = charSet[rBytes[i] % charSet.Length];
    }
    return new string(rName);
}

しかし、あなたは私の新しい(テストされていない)クラスが必要です:

/// <summary>
/// My benchmarking showed that for RNGCryptoServiceProvider:
/// 1. There is negligable benefit of sharing RNGCryptoServiceProvider object reference 
/// 2. Initial GetBytes takes 2ms, and an initial read of 1MB takes 3ms (starting to rise, but still negligable)
/// 2. Cached is ~1000x faster for single byte at a time - taking 9ms over 1MB vs 989ms for uncached
/// </summary>
class SecureFastRandom
{
    static byte[] byteCache = new byte[1000000]; //My benchmark showed that an initial read takes 2ms, and an initial read of this size takes 3ms (starting to raise)
    static int lastPosition = 0;
    static int remaining = 0;

    /// <summary>
    /// Static direct uncached access to the RNGCryptoServiceProvider GetBytes function
    /// </summary>
    /// <param name="buffer"></param>
    public static void DirectGetBytes(byte[] buffer)
    {
        using (var r = new RNGCryptoServiceProvider())
        {
            r.GetBytes(buffer);
        }
    }

    /// <summary>
    /// Main expected method to be called by user. Underlying random data is cached from RNGCryptoServiceProvider for best performance
    /// </summary>
    /// <param name="buffer"></param>
    public static void GetBytes(byte[] buffer)
    {
        if (buffer.Length > byteCache.Length)
        {
            DirectGetBytes(buffer);
            return;
        }

        lock (byteCache)
        {
            if (buffer.Length > remaining)
            {
                DirectGetBytes(byteCache);
                lastPosition = 0;
                remaining = byteCache.Length;
            }

            Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
            lastPosition += buffer.Length;
            remaining -= buffer.Length;
        }
    }

    /// <summary>
    /// Return a single byte from the cache of random data.
    /// </summary>
    /// <returns></returns>
    public static byte GetByte()
    {
        lock (byteCache)
        {
            return UnsafeGetByte();
        }
    }

    /// <summary>
    /// Shared with public GetByte and GetBytesWithMax, and not locked to reduce lock/unlocking in loops. Must be called within lock of byteCache.
    /// </summary>
    /// <returns></returns>
    static byte UnsafeGetByte()
    {
        if (1 > remaining)
        {
            DirectGetBytes(byteCache);
            lastPosition = 0;
            remaining = byteCache.Length;
        }

        lastPosition++;
        remaining--;
        return byteCache[lastPosition - 1];
    }

    /// <summary>
    /// Rejects bytes which are equal to or greater than max. This is useful for ensuring there is no bias when you are modulating with a non power of 2 number.
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="max"></param>
    public static void GetBytesWithMax(byte[] buffer, byte max)
    {
        if (buffer.Length > byteCache.Length / 2) //No point caching for larger sizes
        {
            DirectGetBytes(buffer);

            lock (byteCache)
            {
                UnsafeCheckBytesMax(buffer, max);
            }
        }
        else
        {
            lock (byteCache)
            {
                if (buffer.Length > remaining) //Recache if not enough remaining, discarding remaining - too much work to join two blocks
                    DirectGetBytes(byteCache);

                Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
                lastPosition += buffer.Length;
                remaining -= buffer.Length;

                UnsafeCheckBytesMax(buffer, max);
            }
        }
    }

    /// <summary>
    /// Checks buffer for bytes equal and above max. Must be called within lock of byteCache.
    /// </summary>
    /// <param name="buffer"></param>
    /// <param name="max"></param>
    static void UnsafeCheckBytesMax(byte[] buffer, byte max)
    {
        for (int i = 0; i < buffer.Length; i++)
        {
            while (buffer[i] >= max)
                buffer[i] = UnsafeGetByte(); //Replace all bytes which are equal or above max
        }
    }
}

歴史のために-この答えの私の古い解決策は、ランダムオブジェクトを使用しました:

    private static char[] charSet =
      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();

    static rGen = new Random(); //Must share, because the clock seed only has Ticks (~10ms) resolution, yet lock has only 20-50ns delay.
    static int byteSize = 256; //Labelling convenience
    static int biasZone = byteSize - (byteSize % charSet.Length);
    static bool SlightlyMoreSecurityNeeded = true; //Configuration - needs to be true, if more security is desired and if charSet.Length is not divisible by 2^X.
    public string GenerateRandomString(int Length) //Configurable output string length
    {
      byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
      char[] rName = new char[Length];
      lock (rGen) //~20-50ns
      {
          rGen.NextBytes(rBytes);

          for (int i = 0; i < Length; i++)
          {
              while (SlightlyMoreSecurityNeeded && rBytes[i] >= biasZone) //Secure against 1/5 increased bias of index[0-7] values against others. Note: Must exclude where it == biasZone (that is >=), otherwise there's still a bias on index 0.
                  rBytes[i] = rGen.NextByte();
              rName[i] = charSet[rBytes[i] % charSet.Length];
          }
      }
      return new string(rName);
    }

パフォーマンス:

  1. SecureFastRandom - まず、単一の実行 = 〜9-33ms。知覚できない。継続的な5msの(時にはそれが13msのに上がる)単一の平均反復=で1万人以上の反復、1.5マイクロ秒。。注:通常は2回、場合によっては最大8回のキャッシュリフレッシュが必要です-バイアスゾーンを超えるシングルバイトの数によって異なります
  2. ランダム - 最初の1回の実行 = 〜0-1ms。知覚できない。継続中:10,000回の反復で5ms。単一の平均反復= 0.5マイクロ秒。。ほぼ同じ速度。

またチェックしてください:

これらのリンクは別のアプローチです。この新しいコードベースにバッファリングを追加することもできますが、最も重要なことは、バイアスを取り除くためのさまざまなアプローチを模索し、速度と長所/短所をベンチマークすることでした。


私はたくさんの絶食見えたあなたの方法にいくつかのわずかな性能強化を発見した- stackoverflow.com/a/17092645/1037948を
drzaus

5
1)なぜこれらすべての魔法の定数ですか?出力長を3回指定しました。定数またはパラメータとして定義するだけです。のcharSet.Length代わりに使用できます62。2)Randomロックなしの静的は、このコードがスレッドセーフではないことを意味します。3)0-255 mod 62を減らすと、検出可能なバイアスが生じます。4)ToString常にを返すchar配列では使用できません"System.Char[]"new String(rName)代わりに使用する必要があります。
CodesInChaos

@CodesInChaosに感謝します。当時、私はそれらのことを考えたことはありませんでした。まだRandomクラスのみを使用していますが、これはより良いはずです。バイアス入力を検出して修正するためのこれ以上の方法は考えられませんでした。
トッド

弱いRNG(System.Random)から始めて、独自のコードのバイアスを慎重に回避するのは少しばかげています。「芝を磨く」という表現が思い浮かびます。
CodesInChaos 2016

@CodesInChaosそして見習いは彼の主人を超えました
トッド

4

恐ろしいことですが、私は自分自身を助けることができませんでした:


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


4

私はより具体的な答えを探していました。ランダムな文字列の形式を制御したいのですが、この投稿に出くわしました。例:(車の)ナンバープレートには特定の形式(国ごと)があり、ランダムなナンバープレートを作成したかったのです。
私はこれのためにランダムの独自の拡張メソッドを書くことにしました。(これは、マルチスレッドのシナリオでダブルを使用する可能性があるため、同じRandomオブジェクトを再利用するためです)。私は要旨(https://gist.github.com/SamVanhoutte/808845ca78b9c041e928)を作成しましたが、ここで拡張クラスもコピーします。

void Main()
{
    Random rnd = new Random();
    rnd.GetString("1-###-000").Dump();
}

public static class RandomExtensions
{
    public static string GetString(this Random random, string format)
    {
        // Based on http://stackoverflow.com/questions/1344221/how-can-i-generate-random-alphanumeric-strings-in-c
        // Added logic to specify the format of the random string (# will be random string, 0 will be random numeric, other characters remain)
        StringBuilder result = new StringBuilder();
        for(int formatIndex = 0; formatIndex < format.Length ; formatIndex++)
        {
            switch(format.ToUpper()[formatIndex])
            {
                case '0': result.Append(getRandomNumeric(random)); break;
                case '#': result.Append(getRandomCharacter(random)); break;
                default : result.Append(format[formatIndex]); break;
            }
        }
        return result.ToString();
    }

    private static char getRandomCharacter(Random random)
    {
        string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        return chars[random.Next(chars.Length)];
    }

    private static char getRandomNumeric(Random random)
    {
        string nums = "0123456789";
        return nums[random.Next(nums.Length)];
    }
}

4

ワンライナー風味になりました。

private string RandomName()
{
        return new string(
            Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13)
                .Select(s =>
                {
                    var cryptoResult = new byte[4];
                    using (var cryptoProvider = new RNGCryptoServiceProvider())
                        cryptoProvider.GetBytes(cryptoResult);

                    return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)];
                })
                .ToArray());
}

2
すべてのアクセスで変更される何かにプロパティを使用することはかなり疑わしいです。代わりにメソッドを使用することをお勧めします。
CodesInChaos

2
RNGCryptoServiceProvider使用後は廃棄してください。
Tsahi Asher 2017

IDisposableの問題を修正しましたが、これは依然として非常に疑わしいものであり、文字ごとに新しいRNGCryptoServiceProviderを作成します。
ピオジョ2018年

@CodesInChaosが完了し、メソッドになりました。
Matas Vaitkevicius

3

2つの部分を組み合わせてみてください:一意(シーケンス、カウンターまたは日付)およびランダム

public class RandomStringGenerator
{
    public static string Gen()
    {
        return ConvertToBase(DateTime.UtcNow.ToFileTimeUtc()) + GenRandomStrings(5); //keep length fixed at least of one part
    }

    private static string GenRandomStrings(int strLen)
    {
        var result = string.Empty;

        var Gen = new RNGCryptoServiceProvider();
        var data = new byte[1];

        while (result.Length < strLen)
        {
            Gen.GetNonZeroBytes(data);
            int code = data[0];
            if (code > 48 && code < 57 || // 0-9
                code > 65 && code < 90 || // A-Z
                code > 97 && code < 122   // a-z
                )
            {
                result += Convert.ToChar(code);
            }
        }

        return result;
    }

    private static string ConvertToBase(long num, int nbase = 36)
    {
        var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; //if you wish make algorithm more secure - change order of letter here

        // check if we can convert to another base
        if (nbase < 2 || nbase > chars.Length)
            return null;

        int r;
        var newNumber = string.Empty;

        // in r we have the offset of the char that was converted to the new base
        while (num >= nbase)
        {
            r = (int) (num % nbase);
            newNumber = chars[r] + newNumber;
            num = num / nbase;
        }
        // the last number to convert
        newNumber = chars[(int)num] + newNumber;

        return newNumber;
    }
}

テスト:

[Test]
    public void Generator_Should_BeUnigue1()
    {
        //Given
        var loop = Enumerable.Range(0, 1000);
        //When
        var str = loop.Select(x=> RandomStringGenerator.Gen());
        //Then
        var distinct = str.Distinct();
        Assert.AreEqual(loop.Count(),distinct.Count()); // Or Assert.IsTrue(distinct.Count() < 0.95 * loop.Count())
    }

1)それらの文字に関連付けられたASCII値の代わりに文字リテラルを使用できます。2)間隔一致コードに1つずれた間違いがあります。<=andの>=代わりに<and を使用する必要があり>ます。3)&&優先順位があることを明確にするために、式の周りに不要な括弧を追加しますが、もちろんそれはスタイルの選択にすぎません。
CodesInChaos 2016年

+ 1バイアスの除去とテストの追加に適しています。なぜランダムな文字列の前にタイムスタンプから派生した文字列を付加するのかわかりませんか?また、RNGCryptoServiceProviderを破棄する必要があります
モンティ

2

を使用しないソリューションRandom

var chars = Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 8);

var randomStr = new string(chars.SelectMany(str => str)
                                .OrderBy(c => Guid.NewGuid())
                                .Take(8).ToArray());

2
NewGuidは内部的にランダムを使用します。したがって、これはまだランダムを使用しており、単に非表示にしています。
2016年

2

以下は、WinRT(Windowsストアアプリ)向けのEric Jのソリューションの変種、つまり暗号的に健全なものです。

public static string GenerateRandomString(int length)
{
    var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    var result = new StringBuilder(length);
    for (int i = 0; i < length; ++i)
    {
        result.Append(CryptographicBuffer.GenerateRandomNumber() % chars.Length);
    }
    return result.ToString();
}

パフォーマンスが重要な場合(特に長さが長い場合):

public static string GenerateRandomString(int length)
{
    var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    var result = new System.Text.StringBuilder(length);
    var bytes = CryptographicBuffer.GenerateRandom((uint)length * 4).ToArray();
    for (int i = 0; i < bytes.Length; i += 4)
    {
        result.Append(BitConverter.ToUInt32(bytes, i) % chars.Length);
    }
    return result.ToString();
}

1
これは暗号的に健全ではありません。係数演算により、ulongの幅全体が62文字に均等に拡散されないため、小さなバイアスが発生します。
ライライアン

1

私はこれが最善の方法ではないことを知っています。しかし、これを試すことができます。

string str = Path.GetRandomFileName(); //This method returns a random file name of 11 characters
str = str.Replace(".","");
Console.WriteLine("Random string: " + str);

2
その1行はどうですか?Console.WriteLine($ "ランダム文字列:{Path.GetRandomFileName()。Replace("。 "、" ")}"); 1行です。
PmanAce

1

これがどのように暗号化されているかはわかりませんが、はるかに複雑なソリューションよりも読みやすく簡潔です(imo)System.Random。また、ベースのソリューションよりも「ランダム」である必要があります。

return alphabet
    .OrderBy(c => Guid.NewGuid())
    .Take(strLength)
    .Aggregate(
        new StringBuilder(),
        (builder, c) => builder.Append(c))
    .ToString();

このバージョンまたは次のバージョンが「きれい」であるかどうかを判断することはできませんが、まったく同じ結果が得られます。

return new string(alphabet
    .OrderBy(o => Guid.NewGuid())
    .Take(strLength)
    .ToArray());

もちろん、速度は最適化されていないため、毎秒数百万のランダムな文字列を生成することがミッションクリティカルな場合は、別の文字列を試してください。

注:このソリューションでは、アルファベットの記号を繰り返し使用することはできません。また、アルファベットのサイズは出力文字列と同じかそれ以上である必要があるため、状況によってはこのアプローチが望ましくなく、すべてユースケースによって異なります。


0

値が完全にランダムではないが、実際には何かに依存している場合-その「somwthing」のmd5またはsha1ハッシュを計算してから、必要な長さに切り詰めることができます。

また、GUIDを生成して切り捨てることもできます。


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

2
1)静的メソッドはスレッドセーフでなければなりません。2)random.Next直接の結果を使用する代わりに、インデックスをインクリメントするポイントは何ですか?コードが複雑になり、役立つことは何もありません。
CodesInChaos

0

これは、アルファベットと数字を定義せずにランダムな英数字の文字列を生成するメカニズムです(これを使用してパスワードとテストデータを生成します)。

CleanupBase64は文字列内の必要な部分を削除し、ランダムな英数字を再帰的に追加し続けます。

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

あなたは宣言しているGenerateRandomStringとに電話をかけるGetRandomStringの中からSanitiseBase64String。また、あなたが宣言しているSanitiseBase64String と、コールCleanUpBase64Stringの中でGenerateRandomString
Wai Ha Lee

0

これをとても簡単にする素晴らしいnugetパッケージの 1つがあります

var myObject = new Faker<MyObject>()
.RuleFor(p => p.MyAlphaNumericProperty, f => f.Random.AlphaNumeric(/*lenght*/ 7))
.Generate();

良い例の1つがここにあります


0

ここではすべてのオプションをテストしなかったため、100%確実ではありませんが、テストしたオプションの中で、これが最速です。ストップウォッチでそれを計時し、それは9-10ティックを示したので、スピードがセキュリティよりも重要であるなら、これを試してください:

 private static Random random = new Random(); 
 public static string Random(int length)
     {   
          var stringChars = new char[length];

          for (int i = 0; i < length; i++)
              {
                  stringChars[i] = (char)random.Next(0x30, 0x7a);                  
                  return new string(stringChars);
              }
     }

なぜ返信するのですか?この質問は、多くの時間に答えてきた、まだあなたはまだ半分の作業答えを投稿...
ローラン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.