Rasgele alfasayısal dizeleri nasıl oluşturabilirim?


967

Nasıl C # rastgele 8 karakter alfasayısal bir dize oluşturabilirim?


2
Karakter setinde varsa hangi kısıtlamalar var? Sadece İngilizce karakterler ve 0-9? Karışık dava?
Eric


9
RandomParola oluşturmak için sınıfa dayalı herhangi bir yöntem KULLANMAMANIZ gerektiğini unutmayın . Tohumlama Randomçok düşük entropiye sahiptir, bu yüzden gerçekten güvenli değildir. Parolalar için kriptografik bir PRNG kullanın.
CodesInChaos

2
Bu soruya dil yerelleştirmesini eklemek güzel olurdu. Özellikle gui'nizin Çince veya Bulgarca için yiyecek ve içecek sağlaması gerekiyorsa!
Peter Jamsmenson

15
Bu kadar upvotes ve bu çok kaliteli cevaplar ile bir şey kapalı olarak işaretlenmeyi hak etmiyor. Yeniden açılmasını oyluyorum.
John Coleman

Yanıtlar:


1684

LINQ'nun yeni siyah olduğunu duydum, bu yüzden LINQ kullanma girişimim:

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

(Not: RandomSınıfın kullanımı, parola veya belirteç oluşturma gibi güvenlikle ilgili her şey için uygun değildir . RNGCryptoServiceProviderGüçlü bir rasgele sayı üretecine ihtiyacınız varsa sınıfı kullanın .)


24
@Alex: Birkaç hızlı test yaptım ve daha uzun dizeler oluştururken neredeyse doğrusal olarak ölçekleniyor gibi görünüyor (yeterli bellek olduğu sürece). Bunu söyledikten sonra, Dan Rigby'nin cevabı her testte bunun neredeyse iki katıydı.
LukeH

6
İyi. Ölçütleriniz linq kullanıyorsa ve berbat bir kod anlatısına sahipse, kesinlikle arının dizidir. Hem kod anlatımı hem de fiili uygulama yolu oldukça verimsiz ve dolaylıdır. Beni yanlış anlamayın, ben büyük bir kod hipster (python seviyorum), ama bu hemen hemen bir rube goldberg makinesi.
eremzeit

5
Bu teknik olarak soruyu cevaplarken, çıktısı çok yanıltıcıdır. Olabilir gibi 8 rastgele karakterler sesleri oluşturuluyor çok bu en iyi 2 milyar farklı sonuçlar üretir, oysa fazla sonuç var. Ve pratikte daha az. Güvenlikle ilgili herhangi bir şey için bunu kullanmamak için bir BÜYÜK FAT uyarısı da eklemelisiniz.
CodesInChaos

41
@xaisoft: Küçük harfler okuyucu için bir alıştırma olarak bırakılır.
dtb

15
Aşağıdaki satır, verilen satırdan daha fazla bellek (ve dolayısıyla zaman) verimlidirreturn new string(Enumerable.Range(1, length).Select(_ => chars[random.Next(chars.Length)]).ToArray());
Tyson Williams

375
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 çözümü kadar zarif değil.

(Not: RandomSınıfın kullanımı, parola veya belirteç oluşturma gibi güvenlikle ilgili her şey için uygun değildir . RNGCryptoServiceProviderGüçlü bir rasgele sayı üretecine ihtiyacınız varsa sınıfı kullanın .)


4
@Alex: Bu mutlak en hızlı cevap değil, ama en hızlı "gerçek" cevaptır (yani, kullanılan karakterler ve dizenin uzunluğu üzerinde kontrol sağlayanlar).
LukeH

2
@Alex: Adam Porad'ın GetRandomFileNameçözümü daha hızlıdır, ancak kullanılan karakterlerin kontrolüne izin vermez ve mümkün olan maksimum uzunluk 11 karakterdir. Douglas'ın Guidçözümü yıldırım hızındadır, ancak karakterler A-F0-9 ile sınırlıdır ve mümkün olan maksimum uzunluk 32 karakterdir.
LukeH

1
@Adam: Evet, birden fazla çağrının sonucunu tamamlayabilirsiniz GetRandomFileNameancak (a) performans avantajınızı kaybedersiniz ve (b) kodunuz daha karmaşık hale gelir.
LukeH

1
@xaisoft, döngünüzün dışında Random () nesnesinin örneğini oluşturur. Kısa bir süre içinde çok sayıda Random () örneği oluşturursanız .Next () çağrısı Random () ile aynı değeri döndürerek zamana dayalı bir tohum kullanır.
Dan Rigby

2
@xaisoft Bu yanıtı, parola gibi güvenlik açısından kritik olan herhangi bir şey için kullanmayın. System.Randomgüvenlik için uygun değildir.
CodesInChaos

333

Yorumlara göre GÜNCELLENDİ. Orijinal uygulama, zamanın% ~ 1.95'ini ve kalan karakterler ~% 1.56'sını üretti. Güncelleme tüm karakterleri% ~ 1.61 oranında oluşturur.

ÇERÇEVE DESTEĞİ - .NET Core 3 (ve .NET Standard 2.1 veya üstünü destekleyen gelecekteki platformlar), istenen aralıkta rasgele bir tamsayı oluşturmak için kriptografik olarak sağlam bir yöntem olan RandomNumberGenerator.GetInt32 () sağlar.

Sunulan bazı alternatiflerin aksine, bu kriptografik olarak sağlam .

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

Buradaki alternatiflerin tartışılmasına dayanmaktadır ve aşağıdaki yorumlara göre güncellenmiştir / değiştirilmiştir.

Eski ve güncellenmiş çıktıdaki karakterlerin dağılımını gösteren küçük bir test takımı. Rasgelelik analizinin derinlemesine tartışılması için random.org adresini ziyaret edin.

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
Bu bana doğru yaklaşıma benziyor - hız için optimize edilmiş ve tekrarlanabilir sayı dizileri üreten Random () kullanılarak rastgele şifreler, tuzlar, entropi vb. Üretilmemelidir; Öte yandan RNGCryptoServiceProvider.GetNonZeroBytes (), tekrarlanamayan vahşi sayı dizileri üretir.
mindplay.dk

25
Harfler hafif yanlı (255% 62! = 0). Bu küçük kusura rağmen, buradaki açık ara en iyi çözümdür.
CodesInChaos

13
Bu olduğunu Not değil sen kripto-gücü, tarafsız rasgelelik isterseniz sesi. (Ve sonra neden kullanımını bu istemiyorsanız RNGCSPilk etapta?) İçine endeksine mod kullanarak charssürece çıkış önyargılı alırsınız o dizi araçlarının chars.Length256. bir bölen olur
LukeH

15
Yanlılığı çok azaltmak için bir olasılık, 4*maxSizerastgele bayt istemek , sonra kullanmaktır (UInt32)(BitConverter.ToInt32(data,4*i)% chars.Length. Bunun GetBytesyerine de kullanırdım GetNonZeroBytes. Son olarak, ilk çağrıyı kaldırabilirsiniz GetNonZeroBytes. Sonucunu kullanmıyorsunuz.
CodesInChaos

14
Eğlenceli gerçek: AZ az 0-9 62 karakterdir. İnsanlar mektup önyargısına işaret ediyor çünkü% 256 62! = 0. YouTube'un video kimlikleri AZ az 0-9 ve 256 ile eşit olarak bölünen 64 olası karakter üreten "-" ve "_". Tesadüf? Bence değil! :)
qJake

200

Çözüm 1 - En esnek uzunlukta en büyük 'aralık'

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

Bir GUID her zaman aynı olan ve bu nedenle rasgele olmayan birkaç sabit bite sahip olduğundan, bu çözüm bir GUID kullanmaktan daha fazla aralığa sahiptir, örneğin hex'deki 13 karakter her zaman "4" dür - en azından bir sürüm 6 GUID'sinde.

Bu çözüm, herhangi bir uzunlukta bir dize oluşturmanıza da olanak tanır.

Çözüm 2 - Bir satır kod - 22 karaktere kadar iyi

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

Çözüm 1 olduğu sürece dize oluşturamazsınız ve dize GUID'lerde sabit bitler nedeniyle aynı aralığa sahip değildir, ancak çoğu durumda bu işi yapar.

Çözüm 3 - Biraz daha az kod

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

Çoğunlukla bunu tarihi amaçlarla burada tutmak. Biraz daha az kod kullanır, ancak daha az kapsama alanına sahip olmanın masrafı olarak gelir - base64 yerine hex kullandığından, diğer çözümlere kıyasla aynı aralığı temsil etmek için daha fazla karakter alır.

Bu da çarpışma şansı anlamına gelir - 8 karakter dizisinin 100.000 yinelemesiyle test edilmesi bir kopya oluşturdu.


22
Aslında bir kopya oluşturdunuz mu? 5,316,911,983,139,663,491,615,228,241,121,400,000 olası GUID kombinasyonunda şaşırtıcıdır.
Alex

73
@Alex: GUID'i 8 karaktere kısaltıyor, bu nedenle çarpışma olasılığı GUID'lerden çok daha yüksek.
dtb

23
Hiç kimse nerds dışında bunu takdir edemez :) Evet kesinlikle haklısın, 8 karakter sınırı bir fark yaratıyor.
Alex

31
Guid.NewGuid (). ToString ("n") tire çizgilerini dışarıda tutar, Replace () çağrısı gerekmez. Ancak belirtilmelidir ki, GUID'ler sadece 0-9 ve AF'dir. Kombinasyon sayısı "yeterince iyi" ancak gerçek bir alfasayısal rastgele dizginin izin verdiği yere yakın değil . Çarpışma olasılığı 1: 4,294,967,296'dır - rastgele 32 bitlik bir tamsayı ile aynıdır.
richardtallent

32
1) GUID'ler rastgele değil, benzersiz olacak şekilde tasarlanmıştır. Pencerelerin güncel sürümleri gerçekten rastgele olan V4 GUID'leri oluştururken, bu garanti edilmez. Örneğin, Windows'un eski sürümleri başarısız olabileceğiniz V1 GUID'lerini kullandı. 2) Sadece onaltılık karakterler kullanmak rastgele dizenin kalitesini önemli ölçüde azaltır. 47 ila 32 bit. 3) İnsanlar, bireysel çiftler için verdikleri için çarpışma olasılığını hafife alıyorlar. 100k 32 bit değerleri oluşturursanız, muhtemelen bunlar arasında bir çarpışma olur. Bkz. Doğum günü problemi.
CodesInChaos

72

İşte Dot Net Perls'deki Sam Allen örneğinden çaldığım bir örnek

Yalnızca 8 karaktere ihtiyacınız varsa, System.IO ad alanında Path.GetRandomFileName () öğesini kullanın. Sam, "Buradaki Path.GetRandomFileName yöntemini kullanmanın bazen daha üstün olduğunu söylüyor çünkü daha iyi rasgelelik için RNGCryptoServiceProvider kullanıyor. Ancak, 11 rastgele karakterle sınırlıdır."

GetRandomFileName her zaman 9. karakterde nokta olan 12 karakterlik bir dize döndürür. Bu nedenle, periyodu kesmeniz (rastgele olmadığı için) ve ardından dizeden 8 karakter almanız gerekir. Aslında, ilk 8 karakteri alabilir ve dönem hakkında endişelenmeyebilirsiniz.

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

PS: teşekkürler Sam


27
Bu iyi çalışıyor. 100.000 tekrardan geçtim ve hiçbir zaman yinelenen bir isme sahip değildim. Ancak, ben yaptım (İngilizce) birkaç kaba kelimeleri bulmak. Listedeki ilklerden biri F *** vardı dışında bunu düşünmek olmazdı. Kullanıcının göreceği bir şey için bunu kullanırsanız sadece bir uyarı.
techturtle

3
@techturtle Uyarı için teşekkürler. Sanırım alfabedeki tüm harfleri kullanan herhangi bir rastgele dizgi nesli olan kaba kelimeler için bir risk var.
Adam Porad

güzel ve basit ama uzun dize için iyi değil ... bu iyi hile için oy
Maher Abuthraa

Bu yöntem yalnızca küçük harfli alfasayısal dizeler döndürüyor gibi görünüyor.
jaybro

2
Zaman zaman kaba sözler vardır, ama bunu yeterince uzun süre devam ettirirseniz, Shakespeare yazıyor. (Evrenin sadece birkaç ömrü. :)
Slothario

38

Kodumun ana hedefleri:

  1. Dizelerin dağılımı neredeyse eşittir (küçük oldukları sürece küçük sapmaları umursamayın)
  2. Her bir argüman kümesi için birkaç milyardan fazla karakter dizisi çıkarır. PRNG'niz sadece 2 milyar (31 bit entropi) farklı değerler üretiyorsa, 8 karakterlik bir dize (~ 47 bit entropi) oluşturmak anlamsızdır.
  3. Güvenlidir, çünkü insanların bunu şifreler veya diğer güvenlik belirteçleri için kullanmasını bekliyorum.

İlk özellik, 64 bitlik bir modulo alfabe boyutu alınarak elde edilir. Küçük harfler için (sorudan gelen 62 karakter gibi) bu ihmal edilebilir bir sapmaya yol açar. İkinci ve üçüncü özellik RNGCryptoServiceProvideryerine kullanılarak elde edilir 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 ve Math.Pow (2, Y) ile kesişme yoktur. Bu nedenle, daha büyük sayılar yapmak önyargıyı azaltırken, ortadan kaldırmaz. Cevabımı aşağıda güncelledim, yaklaşımım rastgele girdileri atmak ve başka bir değerle değiştirmekti.
Todd

@Todd Yanlılığı ortadan kaldırmayacağını biliyorum, ama pratik olarak alakasız bir önyargıyı ortadan kaldırmak yerine bu çözümün basitliğini seçtim.
CodesInChaos

Çoğu durumda muhtemelen bununla alakasız olduğunu kabul ediyorum. Ama şimdi benimkini hem rastgele hem de sizinkinden biraz daha güvenli olacak şekilde güncelledim. Herkesin paylaşabileceği açık kaynak. Evet, bu konuda çok fazla zaman harcadım ...
Todd

RNG sağlayıcı kullanıyorsanız, teoride önyargıdan kaçınmanın herhangi bir yolu var mı? Emin değilim ... Todd ek rasgele sayı ürettiğinde (önyargı bölgesinde olduğumuzda) yolu kastediyorsa, yanlış varsayım olabilir. RNG, ortalama olarak üretilen tüm değerlerin neredeyse doğrusal dağılımına sahiptir. Ancak bu, üretilen baytlar arasında yerel bir bağlantımız olmayacağı anlamına gelmez. Bu nedenle, sadece önyargı bölgesi için ek bayt bize bazı önyargılar verebilir, ancak farklı nedenlerden dolayı. Büyük olasılıkla bu önyargı çok küçük olacaktır. ANCAK bu durumda toplam üretilen baytların artması daha basit bir yoldur.
Maxim

1
@Maxim Önyargıyı tamamen ortadan kaldırmak için reddetmeyi kullanabilirsiniz (temeldeki jeneratörün mükemmel rasgele olduğunu varsayarak). Buna karşılık, kod keyfi olarak uzun sürebilir (üstel olarak küçük olasılıkla).
CodesInChaos

32

En basit:

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

Karakter dizisini kodlarsanız ve aşağıdakilere güvenirseniz daha iyi performans elde edebilirsiniz System.Random:

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

İngilizce alfabe zaman zaman değişebilir ve iş kaybedebilir endişelenirseniz, o zaman sert kodlama önleyebilirsiniz, ama biraz daha kötü performans ( Path.GetRandomFileNameyaklaşım ile karşılaştırılabilir ) gerekir

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

Son iki yaklaşım, System.Randomörneğin bir uzantı yöntemi yapabiliyorsanız daha iyi görünür .


1
chars.SelectÇıktı boyutunun en fazla alfabe boyutuna bağlı olması nedeniyle kullanmak çirkin bir şeydir.
CodesInChaos

@CodesInChaos Seni anladığımdan emin değilim. 'a'.To('z')Yaklaşımda mı demek istiyorsun?
nawfal

1
1). chars.Select()(N) `i sadece çalışırsa çalışır chars.Count >= n. Gerçekten kullanmadığınız bir sekansı seçmek, özellikle bu örtülü uzunluk kısıtlamasıyla biraz sezgisel değildir. Enumerable.RangeVeya kullanmayı tercih ederim Enumerable.Repeat. 2) "Son karakter başlangıç ​​karakterinden daha az olmalıdır" hata mesajı yuvarlak / eksik a not.
CodesInChaos

@CodesInChaos ama benim durumumda chars.Countyol > n. Ayrıca kasıtlı olmayan kısmı alamadım. Bu tüm kullanımları Takesezgisel yapmak değil mi? Buna inanmıyorum. Yazım hatasını işaret ettiğiniz için teşekkürler.
nawfal

4
Bu daDailyWTF.com bir CodeSOD makalesi olarak yer almaktadır .

22

Bu konudaki çeşitli cevapların bazı performans karşılaştırmaları:

Yöntemler ve Kurulum

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

Sonuçlar

LinqPad'de test edildi. 10 dize boyutu için şunu üretir:

  • Kaynak Linq = chdgmevhcy [10]
  • Döngü = gtnoaryhxr [10]
  • from Seç = rsndbztyby [10]
  • Kaynak GenerateRandomString = owyefjjakj [10]
  • from SecureFastRandom = VzougLYHYP [10]
  • from SecureFastRandom-NoCache = oVQXNGmO1S [10]

Ve performans numaraları çok nadiren, biraz farklılık eğilimindedir NonOptimizedaslında hızlıdır ve bazen ForLoopve GenerateRandomStringkurşun kimin geçin.

  • LinqIsTheNewBlack (10000x) = 96762 keneler geçti (9.6762 ms)
  • ForLoop (10000x) = geçen 28970 keneler (2.897 ms)
  • Optimize Edilmiş (10000x) = geçen 33336 keneler (3.3336 ms)
  • Tekrar (10000x) = geçen 78547 keneler (7.8547 ms)
  • GenerateRandomString (10000x) = 27416 keneler geçti (2.7416 ms)
  • SecureFastRandom (10000x) = 13176 keneler geçti (5 ms) en düşük [Farklı makine]
  • SecureFastRandom-NoCache (10000x) = 39541 keneler geçti (17 ms) en düşük [Farklı makine]

3
Hangilerinin dupes oluşturduğunu bilmek ilginç olurdu.
Rebecca

@Junto - hangi kopyalarla var many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());değiştirdiğinizi hangi sonuçlarla karşılaştıracağınızı bulmak EachRandomizingMethodiçin ... her yöntem
drzaus


13

Eric J. tarafından yazılan kod oldukça özensizdir (6 yıl önce olduğu oldukça açıktır ... muhtemelen bugün bu kodu yazmaz) ve hatta bazı problemler bile var.

Sunulan bazı alternatiflerin aksine, bu kriptografik olarak sağlam.

Untrue ... Şifrede bir önyargı var (bir yorumda yazıldığı gibi), bcdefghdiğerlerinden biraz daha muhtemeldir ( açünkü GetNonZeroBytessıfır değerine sahip bayt üretmediği için değil, bias içina ) onun tarafından dengelenir, böylece gerçekten şifreli olarak ses değil.

Bu, tüm sorunları düzeltmelidir.

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

Ayrıca rastgele özel dize kullanıyoruz ama bir dizenin yardımcısı olarak uyguladık, bu yüzden biraz esneklik sağlıyor ...

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

kullanım

var random = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".Random();

veya

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

7

Basit bir satır kodum benim için çalışıyor :)

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

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

Herhangi bir uzunluk dizesi için bunu genişletmek için

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

Ben de guid yöntemi gibi - gerçekten hafif hissediyor
ozzy432836

6

Başka bir seçenek Linq kullanmak ve rastgele karakterleri bir dize oluşturucuda toplamak olabilir.

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

Soru: Yazmak Enumerable.Rangeyerine neden zamanımı harcayayım "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;
    }
}

Cevap: Sihirli teller KÖTÜ. HERHANGİ BİR "I üstteki " mi? Annem bana bu nedenle sihirli teller kullanmamayı öğretti ...

nb 1: @dtb gibi birçok kişinin söylediği gibi, System.Randomşifreleme güvenliğine ihtiyacınız varsa kullanmayın ...

nb 2: Bu cevap en verimli ya da en kısa değil, ama cevabı sorudan ayırmak için alanın olmasını istedim. Cevabımın amacı, süslü yenilikçi bir cevap sunmaktan ziyade sihirli iplere karşı uyarmaktır.


Neden hiç " I?"
Christine

1
Alfasayısal (yoksayma durumu) 'dir [A-Z0-9]. Yanlışlıkla, rastgele dizeniz [A-HJ-Z0-9]sonucu yalnızca hiç kapsıyorsa , sorunlu olabilecek izin verilen tüm aralığı kapsamaz.
Wai Ha Lee

Bu nasıl sorunlu olurdu? Yani içermiyor I. Çünkü daha az karakter var ve bu çatlamayı kolaylaştırıyor mu? 36'dan daha fazla 35 karakter içeren kırılabilir parolalar hakkında istatistikler nelerdir. Sanırım onu ​​riske atmayı tercih ederim ... ya da sadece karakter aralığını silmeyi tercih ederim ... kodumdaki tüm ekstra çöpleri içermekten çok. Ama o benim. Yani, popo deliği olmamak için, sadece söylüyorum. Bazen programcıların ekstra karmaşık olma uğruna ekstra karmaşık rotaya gitme eğilimi olduğunu düşünüyorum.
Christine

1
Kullanım durumuna derinlemesine bakar. Bu gibi karakterleri çıkarmak için çok yaygındır Ive Oonlara kafa karıştırıcı insanları engellemek için rastgele dizeleri bu tür gelen 1ve 0. İnsan tarafından okunabilir bir dizeye sahip olmakla ilgilenmiyorsanız, iyi, ancak birisinin yazması gerekebilecek bir şey varsa, o karakterleri kaldırmak gerçekten akıllıdır.
Chris Pratt

5

DTB'nin çözümünün biraz daha temiz bir versiyonu.

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

Stil tercihleriniz değişebilir.


Bu, kabul edilen cevaptan çok daha iyi ve daha verimlidir.
Kama

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

Diğer cevapları inceledikten ve CodeInChaos'un yorumlarını düşündükten sonra, CodeInChaos ile birlikte hala (daha az olmasına rağmen) yanıtı taraflı olarak, son bir nihai kesme ve yapıştırma çözümü düşündüm ihtiyaç . Bu yüzden cevabımı güncellerken tüm dışarı çıkmaya karar verdim.

Bu kodun güncel bir sürümü için lütfen Bitbucket'teki yeni Hg deposunu ziyaret edin: https://bitbucket.org/merarischroeder/secureswiftrandom . Kodu kopyalamanızı ve yapıştırmanızı tavsiye ederim: https://bitbucket.org/merarischroeder/secureswiftrandom/src/6c14b874f34a3f6576b0213379ecdf0ffc7496ea/Code/Alivate.SolidSwiftRandom/SolidSwileRde/fa/fa/fa/fa/ (marka emin tıklayın Kopyala ve en son sürüme sahip olduğunuzdan emin olmak için Raw düğmesi, bu bağlantının en son değil, kodun belirli bir sürümüne gittiğini düşünüyorum).

Güncellenmiş notlar:

  1. Diğer bazı yanıtlarla ilgili olarak - Çıktının uzunluğunu biliyorsanız, bir StringBuilder'a ihtiyacınız yoktur ve ToCharArray kullanırken, bu dizi oluşturulur ve doldurulur (önce boş bir dizi oluşturmanız gerekmez)
  2. Diğer bazı cevaplarla ilgili olarak - Performans için birer birer almak yerine NextBytes kullanmalısınız
  3. Teknik olarak, daha hızlı erişim için bayt dizisini sabitleyebilirsiniz .. bir bayt dizisi üzerinde 6-8 kereden fazla yinelediğinizde genellikle buna değer. (Burada yapılmadı)
  4. Kullanımı En iyi rastgelelik için RNGCryptoServiceProvider
  5. Kullanımı rastgele veri 1 MB tamponu önbelleğe - önbelleğe alınmamış için 989ms vs 1MB üzerinde 9ms alarak - benchmarking gösterileri tek bayt erişim hızı daha hızlı ~ 1000x olduğunu önbelleğe.
  6. Yeni sınıfımdaki önyargı bölgesinin reddedilmesi optimize edildi .

Soruya son çözüm:

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

Ama yeni (denenmemiş) dersime ihtiyacın var:

/// <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
        }
    }
}

Tarih için - bu cevap için eski çözümüm, Random nesnesini kullandı:

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

Verim:

  1. SecureFastRandom - İlk tek çalıştırma = ~ 9-33ms . Algılanamaz. Devam eden : 10.000 yinelemede 5ms (bazen 13ms'ye kadar), Tek bir ortalama yineleme = 1.5 mikrosaniye.. Not: Genellikle 2, ancak bazen 8 önbellek yenilemesi gerektirir - kaç tek baytın bias bölgesini aştığına bağlıdır.
  2. Rastgele - İlk tek çalıştırma = ~ 0-1 ms . Algılanamaz. Devam eden : 10.000 yinelemeden 5 ms . Tek bir ortalama yineleme ile = .5 mikrosaniye. . Aynı hızda.

Ayrıca şunu da kontrol et:

Bu bağlantılar başka bir yaklaşımdır. Tamponlama bu yeni kod tabanına eklenebilir, ancak en önemlisi önyargıların giderilmesi ve hızların ve artıların / eksilerin karşılaştırılması için farklı yaklaşımlar araştırmaktı.



5
1) Neden bütün bu sihirli sabitler? Çıkış uzunluğunu üç kez belirttiniz. Sadece sabit veya parametre olarak tanımlayın. Bunun charSet.Lengthyerine kullanabilirsiniz 62. 2) RandomKilitlemesiz statik , bu kodun emniyetli olmadığı anlamına gelir. 3) 0-255 mod 62'nin azaltılması saptanabilir bir sapma getirir. 4) Her ToStringzaman dönen bir char dizisinde kullanamazsınız "System.Char[]". Bunun new String(rName)yerine kullanmanız gerekir .
CodesInChaos

@CodesInChaos'a teşekkürler, o zamanlar bunları hiç düşünmemiştim. Yine de sadece Random sınıfı kullanıyor, ama bu daha iyi olmalı. Önyargı girdilerini tespit etmek ve düzeltmek için daha iyi bir yol düşünemedim.
Todd

Zayıf bir RNG ( System.Random) ile başlamak ve kendi kodunuzdaki herhangi bir önyargıdan dikkatle kaçınmak biraz aptalca . "Balığı parlatma" ifadesi akla geliyor.
CodesInChaos

@CodesInChaos Ve şimdi çırak efendisini aştı
Todd

4

Korkunç, biliyorum, ama kendime yardım edemedim:


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

Rastgele dizenin biçimini kontrol etmek istediğim ve bu yazıyla karşılaştığım daha spesifik bir cevap arıyordum. Örneğin: plakaların (araçların) belirli bir formatı (ülke başına) var ve ben rasgele plakalar oluşturmak istedim.
Bunun için kendi Rastgele uzatma yöntemimi yazmaya karar verdim. (bu, çoklu iş parçacığı senaryolarında iki katına sahip olabileceğiniz için aynı Rastgele nesneyi yeniden kullanmak içindir). Bir gist oluşturdum ( https://gist.github.com/SamVanhoutte/808845ca78b9c041e928 ), ancak uzantı sınıfını da buraya kopyalayacağım:

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

Şimdi tek astarlı bir lezzet.

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
Her erişimde değişen bir şey için bir özellik kullanmak oldukça şüphelidir. Bunun yerine bir yöntem kullanmanızı öneririm.
CodesInChaos

2
RNGCryptoServiceProviderkullanımdan sonra atılmalıdır.
Tsahi Asher

IDisposable sorununu düzelttim, ancak bu hala çok şüpheli, her harf için yeni bir RNGCryptoServiceProvider oluşturuyor.
piojo

@CodesInChaos bitti, şimdi bir yöntem.
Matas Vaitkevicius

3

İki parçayı birleştirmeye çalışın: benzersiz (sıra, sayaç veya tarih) ve rastgele

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

Testler:

[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) Bu karakterlerle ilişkili ASCII değerleri yerine karakter değişmez değerlerini kullanabilirsiniz. 2) Aralık eşleme kodunuzda bire bir hata var. Sen kullanmak gerekir <=ve >=yerine <ve >. 3) Önceliğe &&sahip olduklarını açıkça belirtmek için ifadelerin etrafına gereksiz parantezler eklerdim, ama elbette bu sadece stilistik bir seçim.
CodesInChaos

+ 1 Yanlılığı gidermek ve test eklemek için iyidir. Neden rastgele bir zaman damgası türetilmiş dize ile rasgele dize tercih emin değilim? Ayrıca, hala RNGCryptoServiceProvider
monty

2

Kullanmadan bir çözüm Random:

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

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

2
NewGuid dahili olarak rastgele kullanır. Yani bu hala rastgele kullanıyor, sadece saklıyor.
Kama

2

İşte WinRT (Windows Store Uygulaması) için Eric J çözümünün bir çeşidi, yani kriptografik olarak ses:

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

Performans önemliyse (özellikle uzunluk yüksek olduğunda):

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
Bu kriptografik olarak sağlam değil . Tüm ulong genişliğini 62 karaktere eşit olarak yaymayan modül işleminden dolayı küçük bir önyargı vardır.
Yalan Ryan

1

Bunun en iyi yol olmadığını biliyorum. Ama bunu deneyebilirsiniz.

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

2
Bu nasıl bir çizgi? Console.WriteLine ($ "Rastgele dize: {Path.GetRandomFileName (). Değiştir (". "," ")}"); bir satırdır.
PmanAce

1

Kriptografik olarak bunun ne kadar sesli olduğunu bilmiyorum, ama bugüne kadar (imo) daha karmaşık çözümlerden daha okunabilir ve özlü ve System.Randomtemelli çözümlerden daha "rastgele" olmalı .

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

Ben bu sürümü veya bir sonraki "güzel" olup olmadığına karar veremem, ama aynı sonuçları verir:

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

Verilmiş, hız için optimize edilmemiştir, bu nedenle her saniye milyonlarca rastgele dizge oluşturmak kritik önem taşıyorsa, başka bir tane deneyin!

NOT: Bu çözüm, alfabedeki sembollerin tekrarına izin vermez ve alfabe, çıktı dizesinden eşit veya daha büyük boyutta olmalıdır ZORUNLU, bu yaklaşımı bazı durumlarda daha az istenir hale getirir, hepsi kullanım durumunuza bağlıdır.


0

Değerleriniz tamamen rasgele değilse, ama aslında bir şeye bağlı olabilirse - o 'bir şeyin' bir md5 veya sha1 karmasını hesaplayabilir ve daha sonra istediğiniz uzunlukta kısaltabilirsiniz.

Ayrıca bir rehber oluşturabilir ve kesebilirsiniz.


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) statik yöntemler diş güvenli olmalıdır. 2) random.NextDoğrudan sonucu kullanmak yerine endeksi artırmanın anlamı nedir ? Kodu karmaşık hale getirir ve yararlı bir şey elde etmez.
CodesInChaos

0

Alfabe ve sayıları tanımlamadan rastgele bir alfasayısal dize (parola ve test verileri oluşturmak için kullanıyorum) oluşturmak için bir mekanizma,

CleanupBase64, dizede gerekli parçaları kaldıracak ve yinelemeli olarak rasgele alfasayısal harfler eklemeye devam edecektir.

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

İçeriden ilan ettiniz GenerateRandomStringve bir arama GetRandomStringyaptınız SanitiseBase64String. Ayrıca ilan ettiler SanitiseBase64String ve çağrı CleanUpBase64Stringiçinde GenerateRandomString.
Wai Ha Lee

0

Bunu bu kadar basit hale getiren awasome nuget paketlerinden biri var .

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

Bunun güzel bir örneği burada .


0

% 100 emin değilim, burada HER seçeneğini test etmedim, ama test ettiğimlerden en hızlısı bu. kronometre ile zamanladı ve 9-10 keneler gösterdi, bu nedenle hız güvenlikten daha önemliyse şunu deneyin:

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

Neden cevap verelim? Bu soru birçok kez cevaplandı ve yine de yarı çalışan cevabını
Laurent
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.