임의의 영숫자 문자열을 어떻게 생성 할 수 있습니까?


967

C #에서 임의의 8 자 영숫자 문자열을 생성하려면 어떻게해야합니까?


2
문자 세트에 어떤 제한이 있습니까? 영어 문자와 0-9입니까? 혼합 사례?
Eric J.


9
Random비밀번호를 생성하기 위해 클래스를 기반으로하는 메소드를 사용해서는 안됩니다 . 시딩은 Random엔트로피가 매우 낮으므로 실제로 안전하지 않습니다. 암호에는 암호화 PRNG를 사용하십시오.
코드 InChaos

2
이 질문에 언어 현지화를 포함시키는 것이 좋을 것입니다. 특히 귀하의 GUI가 중국어 또는 불가리아어를 수용 해야하는 경우!
Peter Jamsmenson

15
이 많은 공감대와이 많은 질적 인 답변이있는 것은 폐쇄 된 것으로 표시 될 가치가 없습니다. 나는 그것이 다시 열리게 투표합니다.
John Coleman

답변:


1684

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
@ Alex : 몇 가지 빠른 테스트를 실행했으며 더 긴 문자열을 생성 할 때 (실제로 충분한 메모리가있는 한) 거의 선형으로 확장되는 것으로 보입니다. Dan Rigby의 대답은 모든 테스트 에서이 것보다 거의 두 배 빠릅니다.
LukeH

6
잘. 당신의 기준이 linq를 사용하고 코드 설명이 거칠다면 그것은 확실히 꿀벌의 무릎입니다. 코드 설명과 실제 실행 경로는 다소 비효율적이며 간접적입니다. 나를 잘못 이해하지 마라. 나는 거대한 코드 힙 스터 (파이썬을 좋아한다)이지만 이것은 루브 골드 베르그 기계와 거의 비슷하다.
eremzeit

5
이것은 기술적으로 질문에 대답하지만 결과는 매우 오도됩니다. 8 개의 임의의 문자를 생성하면 매우 많은 결과 가 나오는 것처럼 들릴 수 있지만 , 결과적으로 20 억 개의 다른 결과가 생성됩니다. 실제로는 훨씬 적습니다. 또한 보안 관련 사항에 이것을 사용하지 않으려면 BIG FAT 경고를 추가해야합니다.
코드 InChaos

41
@xaisoft : 소문자는 독자를위한 연습으로 남습니다.
dtb

15
다음 라인은 주어진 것보다 더 많은 메모리 (따라서 시간이 효율적)입니다return 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 솔루션만큼 우아하지는 않습니다.

(참고 : Random클래스를 사용하면 암호 또는 토큰 생성과 같은 보안 관련 항목에 적합하지 않습니다 . RNGCryptoServiceProvider강력한 난수 생성기가 필요한 경우 클래스를 사용하십시오 .)


4
@Alex : 이것은 가장 빠른 답변은 아니지만 가장 빠른 "실제"답변입니다 (즉, 사용 된 문자와 문자열 길이를 제어 할 수있는 답변).
LukeH

2
@Alex : Adam Porad의 GetRandomFileName솔루션은 더 빠르지 만 사용 된 문자를 제어 할 수 없으며 가능한 최대 길이는 11 자입니다. Douglas의 Guid솔루션은 매우 빠르지 만 문자는 A-F0-9로 제한되며 가능한 최대 길이는 32 자입니다.
LukeH

1
@Adam : 예, 여러 번의 호출 결과를 연결할 수는 GetRandomFileName있지만 (a) 성능 이점을 잃게되고 (b) 코드가 더 복잡해집니다.
LukeH

1
@xaisoft는 루프 외부에서 Random () 객체의 인스턴스를 만듭니다. 짧은 간격으로 많은 Random () 인스턴스를 만들면 .Next () 호출은 Random ()이 시간 기반 시드를 사용하는 것과 동일한 값을 반환합니다.
Dan Rigby

2
@xaisoft 비밀번호와 같은 보안에 중요한 것은이 답변을 사용하지 마십시오. System.Random보안에 적합하지 않습니다.
코드 InChaos

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

대안의 논의를 바탕으로 여기에 아래 의견에 따라 업데이트 / 수정 .

다음은 이전 및 업데이트 된 출력의 문자 분포를 보여주는 작은 테스트 장치입니다. randomness 분석에 대한 자세한 내용은 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

25
글자는 약간 편향되어 있습니다 (255 % 62! = 0). 이 작은 결함에도 불구하고, 지금까지 가장 좋은 해결책입니다.
코드 InChaos

13
크립토 강도, 편견없는 임의성을 원하는 경우 에는 소리 가 나지 않습니다 . (그리고 만약 당신이 그것을 원하지 않는다면 왜 RNGCSP처음에 사용 하는가?) mod를 사용하여 chars배열 을 색인 하는 것은 chars.Length256의 제수가 되지 않는 한 편향된 결과를 얻는다는 것을 의미합니다.
LukeH

15
바이어스를 많이 줄이는 한 가지 가능성은 4*maxSize임의 바이트를 요청한 다음을 사용하는 것 (UInt32)(BitConverter.ToInt32(data,4*i)% chars.Length입니다. GetBytes대신을 사용 합니다 GetNonZeroBytes. 마지막으로에 대한 첫 번째 호출을 제거 할 수 있습니다 GetNonZeroBytes. 결과를 사용하지 않습니다.
코드 InChaos

14
재미있는 사실 : AZ az 0-9는 62 자입니다. 256 % 62! = 0이므로 사람들은 글자 편견을 지적하고 있습니다. YouTube의 동영상 ID는 AZ az 0-9이며 "-"및 "_"는 64 개의 가능한 문자를 생성하여 256으로 균등하게 나눕니다. 우연의 일치? 나는 그렇게 생각하지 않는다! :)
qJake

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에는 항상 동일하고 임의적이지 않은 고정 된 비트가 두 개 있기 때문에 16 진수로 된 13자는 항상 "4"입니다. 최소한 버전 6 GUID에서는.

이 솔루션을 사용하면 모든 길이의 문자열을 생성 할 수 있습니다.

해결 방법 2-한 줄의 코드-최대 22 자에 적합

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

솔루션 1 만큼 문자열을 생성 할 수 없으며 GUID의 고정 비트로 인해 문자열의 범위가 동일하지 않지만 대부분의 경우이 작업을 수행합니다.

해결 방법 3-약간 적은 코드

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

대부분 역사적 목적으로 여기에 보관하십시오. 약간 적은 코드를 사용하지만 범위를 줄이는 데 드는 비용이 들지만 base64 대신 16 진수를 사용하기 때문에 다른 솔루션과 동일한 범위를 나타내는 데 더 많은 문자가 필요합니다.

이는 더 많은 충돌 가능성을 의미합니다. 8 개의 문자열을 100,000 번 반복하여 테스트하면 하나의 사본이 생성됩니다.


22
실제로 복제본을 생성 했습니까? 5,316,911,983,139,663,491,615,228,241,121,400,000의 가능한 GUID 조합에 놀랍습니다.
Alex

73
@Alex : GUID를 8 자로 줄이므로 충돌 가능성이 GUID보다 훨씬 높습니다.
dtb

23
아무도 괴상한 것 외에는 이것을 이해할 수 없습니다 :) 그렇습니다 .8 자 제한은 차이를 만듭니다.
Alex

31
Guid.NewGuid (). ToString ( "n")은 대시를 유지하며 Replace () 호출이 필요하지 않습니다. 그러나 GUID는 0-9와 AF에 불과합니다. 조합의 수는 "충분히"우수하지만 실제 영숫자 임의 문자열이 허용 하는 것과 거의 일치하지 않습니다 . 충돌 가능성은 임의의 32 비트 정수와 동일한 1 : 4,294,967,296입니다.
richardtallent

32
1) GUID는 무작위가 아닌 고유하도록 설계되었습니다. 현재 버전의 Windows는 실제로 임의의 V4 GUID를 생성하지만 보장되지는 않습니다. 예를 들어, 이전 버전의 창에서는 V1 GUID를 사용했는데 실패 할 수있었습니다. 2) 16 진 문자 만 사용하면 임의 문자열의 품질이 크게 저하됩니다. 47에서 32 비트 3) 사람들은 개별 쌍에 대해 충돌 확률을 제공하므로 충돌 확률을 과소 평가합니다. 100k 32 비트 값을 생성하면 그 중 하나의 충돌이있을 수 있습니다. 생일 문제를 참조하십시오.
코드 InChaos

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
}

추신 : 감사합니다 샘


27
이것은 잘 작동합니다. 나는 100,000 번의 반복을 통해 그것을 실행했으며 결코 중복 된 이름이 없었습니다. 그러나, 나는 않았다 (영어) 여러 저속한 단어를 찾을 수 있습니다. 목록의 첫 번째 항목 중 하나에 F ***가 있다는 점을 제외하고는 이것을 생각조차하지 않았을 것입니다. 사용자가 볼 수있는 무언가에 이것을 사용하면 머리 위로 올라갑니다.
techturtle

3
@techturtle 경고 해 주셔서 감사합니다. 알파벳의 모든 문자를 사용하는 임의의 문자열 생성으로 저속한 단어에 위험이 있다고 가정합니다.
Adam Porad

멋지고 단순하지만 긴 문자열에는 좋지 않습니다 ...이 좋은 트릭에 투표
Maher Abuthraa

이 방법은 소문자 영숫자 문자열 만 반환하는 것 같습니다.
jaybro

2
때때로 저속한 단어가 있지만, 이것을 오랫동안 오래 사용하면 결국 셰익스피어가됩니다. (우주의 몇 평생.)
Slothario

38

내 코드의 주요 목표는 다음과 같습니다.

  1. 줄의 분포는 거의 균일합니다 (작은 한 작은 편차는 신경 쓰지 마십시오)
  2. 각 인수 세트에 대해 수십억 개 이상의 문자열을 출력합니다. PRNG가 20 억 (31 비트의 엔트로피) 만 다른 값을 생성하는 경우 8 문자열 (~ 47 비트의 엔트로피)을 생성하는 것은 의미가 없습니다.
  3. 사람들이 암호 또는 다른 보안 토큰에 이것을 사용할 것으로 기대하기 때문에 안전합니다.

첫 번째 속성은 알파벳 크기의 64 비트 값 모듈로를 취함으로써 달성됩니다. 작은 알파벳 (예 : 질문의 62 자)의 경우 이는 무시할만한 편향으로 이어집니다. 두 번째 및 세 번째 속성은 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

@Todd 나는 그것이 바이어스를 제거하지는 않는다는 것을 알고 있지만, 실제로 관련이없는 바이어스를 제거하는 것 보다이 솔루션의 단순성을 선택했습니다.
코드 InChaos

나는 대부분의 경우에 실제로 관련이 없다고 동의합니다. 그러나 이제는 임의의 속도와 속도보다 안전하도록 업데이트했습니다. 모두가 공유 할 수있는 모든 공개 소스. 그렇습니다, 나는 이것에 너무 많은 시간을 낭비했습니다 ...
Todd

RNG 공급자를 사용하는 경우 이론적으로 편견을 피할 수있는 방법이 있습니까? 확실하지 않습니다 ... Todd가 추가 난수를 생성하는 방식을 의미한다면 (바이어스 구역에있을 때) 잘못된 가정 일 수 있습니다. RNG는 평균적으로 모든 생성 된 값의 선형 분포를 갖습니다. 그러나 생성 된 바이트간에 로컬 상관 관계가 없음을 의미하지는 않습니다. 따라서 바이어스 영역의 추가 바이트 만 여전히 약간의 바이어스를 줄 수 있지만 다른 이유가 있습니다. 이 편향은 매우 작을 것입니다. 그러나이 경우 총 생성 바이트 수를 늘리는 것이 더 간단합니다.
Maxim

1
@Maxim 거부를 사용하여 바이어스를 완전히 제거 할 수 있습니다 (기본 생성기가 완전히 임의의 것으로 가정). 그 대가로 코드는 임의적으로 길어질 수있다 (지수 적으로 작은 확률로).
코드 InChaos

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

마지막 두 가지 접근 방식을 확장 방법으로 만들면 더 좋아 보입니다. System.Random 인스턴스 .


1
chars.Select출력 크기가 최대 알파벳 크기에 의존하기 때문에 사용 이 크게 추악합니다.
코드 InChaos

@CodesInChaos 내가 당신을 이해하는지 잘 모르겠습니다. 당신은 'a'.To('z')접근 에서 의미 합니까?
nawfal

1
1) chars.Select().Take (n)`은 경우에만 작동합니다 chars.Count >= n. 실제로 사용하지 않는 시퀀스를 선택하는 것은 특히 암시 적 길이 제약 조건과 관련하여 약간 직관적이지 않습니다. 오히려 Enumerable.Range또는을 사용하고 싶습니다 Enumerable.Repeat. 2) "끝 문자는 시작 문자보다 작아야합니다"라는 오류 메시지가 잘못 표시 not됩니다.
코드 InChaos

@CodesInChaos하지만 제 경우 chars.Count에는 방법 > n입니다. 또한 나는 직관적이지 않은 부분을 얻지 못합니다. 그것은 모든 사용이 Take직관적이지 않습니까? 나는 그것을 믿지 않는다. 오타를 지적 해 주셔서 감사합니다.
nawfal

4
이것은 DailyWTF.com 에서 CodeSOD 기사로 제공됩니다.

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]
  • from 루프 = gtnoaryhxr [10]
  • 선택에서 = rsndbztyby [10]
  • From GenerateRandomString = owyefjjakj [10]
  • SecureFastRandom에서 = VzougLYHYP [10]
  • SecureFastRandom-NoCache에서 = oVQXNGmO1S [10]

그리고 성능 수치는 아주 가끔, 약간 다를하는 경향이 NonOptimized실제로 빠르게, 때로는 ForLoopGenerateRandomString리드에 누가 전환합니다.

  • LinqIsTheNewBlack (10000x) = 96762 틱 경과 (9.6762ms)
  • ForLoop (10000x) = 28970 틱 (2.897ms) 경과
  • ForLoopNonOptimized (10000x) = 33336 틱 경과 (3.3336ms)
  • 반복 (10000x) = 78547 틱 경과 (7.8547ms)
  • GenerateRandomString (10000x) = 27416 틱 경과 (2.7416ms)
  • SecureFastRandom (10000x) = 최저 13176 틱 (5ms) 최저 [다른 시스템]
  • SecureFastRandom-NoCache (10000x) = 39541 틱 (17ms) 최저 [다른 시스템]

3
어느 쪽이 듀피를 만들 었는지 아는 것은 흥미로울 것입니다.
Rebecca

@Junto-어떤 방법으로 복제 할 것인지를 알아 내기 var many = 10000; Assert.AreEqual(many, new bool[many].Select(o => EachRandomizingMethod(10)).Distinct().Count());위해 EachRandomizingMethod... 각 방법으로 대체
drzaus

19

한 줄의 코드 Membership.GeneratePassword()가 트릭을 수행합니다. :)

다음은 동일한 데모 입니다.



나는 그것을 생각했지만 두 번째 논거가 최소 비 알파 문자이기 때문에 영숫자가 아닌 문자를 제거 할 수 없었습니다
ozzy432836

13

Eric J.가 작성한 코드는 매우 조잡합니다 (6 년 전의 코드임을 분명히 알 수 있습니다. 아마도 그는 오늘 그 코드를 쓰지 않았을 것입니다).

제시된 대안 중 일부와는 달리, 이것은 암호화 적으로 건전합니다.

사실이 아닙니다 ... (비고에 쓰여진) 비밀번호에 편견 bcdefgh이 있고 다른 것보다 조금 더 가능성이 있습니다 ( 값이 0 인 바이트를 생성 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

내 간단한 한 줄 코드가 나를 위해 작동합니다 :)

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를 사용하고 무작위 문자를 stringbuilder로 집계하는 것입니다.

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입니까?
Christine

1
영숫자 (대소 문자 무시)는 [A-Z0-9]입니다. 실수로 임의의 문자열 만 [A-HJ-Z0-9]결과를 덮는 경우 전체 허용 범위를 다루지 않는 경우 문제가 될 수 있습니다.
Wai Ha Lee

어떻게 문제가 될까요? 을 포함하지 않습니다 I. 캐릭터가 적고 깨지기 쉽기 때문입니까? 36보다 35 문자를 포함하는 크래킹 가능한 암호에 대한 통계는 무엇입니까? 코드에 여분의 쓰레기를 모두 포함시키는 것보다 위험을 감수 할 것입니다. 그러나 그것은 저입니다. 엉덩이 구멍이 아니라는 말입니다. 때로는 프로그래머가 복잡한 것을 피하기 위해 여분의 복잡한 길을가는 경향이 있다고 생각합니다.
Christine

1
유스 케이스에 대해 자세히 설명합니다. 이러한 유형의 임의 문자열 I과 같은 문자를 제외 하고 O사람이 1and와 혼동하지 않도록하는 것이 매우 일반적 0입니다. 사람이 읽을 수있는 문자열에 신경 쓰지 않아도 괜찮지 만 누군가 입력해야 할 경우 실제로 해당 문자를 제거하는 것이 좋습니다.
Chris Pratt

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

선호하는 스타일은 다를 수 있습니다.


이것은 허용 된 답변보다 훨씬 낫고 효율적입니다.
웨지

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. 다른 답변과 관련-성능을 위해 한 번에 하나씩 얻는 대신 NextBytes를 사용해야합니다.
  3. 기술적으로보다 빠른 액세스를 위해 바이트 배열을 고정 할 수 있습니다. 일반적으로 바이트 배열에서 6-8 회 이상 반복 할 때 유용합니다. (여기서는 안됨)
  4. 최상의 무작위성을 위해 RNGCryptoServiceProvider 사용
  5. 임의 데이터의 1MB 버퍼 캐싱 사용 -벤치마킹은 캐시 된 단일 바이트 액세스 속도가 ~ 1000 배 빠르다는 것을 보여줍니다.
  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
        }
    }
}

역사-이 대답에 대한 나의 오래된 해결책은 Random 객체를 사용했습니다.

    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 . 이해할 수 없습니다. 진행 중 : 10,000 회 이상 5ms (때로는 최대 13ms), 단일 평균 반복 = 1.5 마이크로 초. . 참고 : 일반적으로 2 개, 때로는 최대 8 개의 캐시 새로 고침이 필요합니다. 바이어스 영역을 초과하는 단일 바이트 수에 따라 다릅니다.
  2. Random - First 단일 실행 = ~ 0-1ms . 이해할 수 없습니다. 진행 중 : 10,000 회 이상 5ms 단일 평균 반복 = 0.5 마이크로 초 . 같은 속도입니다.

또한 확인하십시오 :

이 링크는 또 다른 접근법입니다. 이 새로운 코드베이스에 버퍼링을 추가 할 수 있었지만, 가장 중요한 것은 바이어스를 제거하고 속도와 장단점을 벤치마킹하는 다양한 방법을 모색하는 것이 었습니다.


- 나는 당신하여 무리 금식 보였다 방법에 약간의 성능 향상을 볼 stackoverflow.com/a/17092645/1037948
drzaus

5
1) 왜 모든 마법 상수가 있습니까? 출력 길이를 번 지정했습니다 . 상수 또는 매개 변수로 정의하십시오. charSet.Length대신 사용할 수 있습니다 62. 2) Random잠금이없는 정적 은이 코드가 스레드 안전하지 않다는 것을 의미합니다. 3) 0-255 mod 62를 줄이면 감지 가능한 바이어스가 발생합니다. 4) ToStringchar 배열 에는 사용할 수 없으며 항상을 반환합니다 "System.Char[]". new String(rName)대신 사용해야 합니다.
코드 InChaos

@CodesInChaos 덕분에 그 당시에는 그런 생각을 한 적이 없었습니다. 여전히 Random 클래스 만 사용하지만 더 좋습니다. 바이어스 입력을 감지하고 수정하는 더 좋은 방법을 생각할 수 없었습니다.
Todd

약한 RNG ( System.Random)로 시작한 다음 자신의 코드에서 편견을 조심스럽게 피하는 것은 약간 어리 석습니다 . "똥 깍기"라는 표현이 떠 오릅니다.
코드 InChaos

@CodesInChaos 그리고 이제 도제는 그의 주인을 능가했습니다
Todd

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
모든 액세스에서 변경되는 속성을 사용하는 것은 다소 모호합니다. 대신 방법을 사용하는 것이 좋습니다.
코드 InChaos

2
RNGCryptoServiceProvider사용 후 폐기해야합니다.
Tsahi Asher

IDisposable 문제를 해결했지만 각 문자마다 새로운 RNGCryptoServiceProvider를 작성하는 것은 여전히 ​​모호합니다.
piojo

@CodesInChaos가 완료되었습니다. 이제 방법입니다.
Matas Vaitkevicius

3

고유 (순서, 카운터 또는 날짜) 및 임의의 두 부분을 결합하십시오.

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) 간격 일치 코드에 실수가 있습니다. 당신은 사용해야 <=하고 >=대신 <>. 3) &&표현식에 불필요한 괄호를 추가하여 우선 순위가 있음을 분명히하지만 물론 스타일 선택입니다.
코드 InChaos

+ 1 바이어스를 제거하고 테스트를 추가하는 데 좋습니다. 왜 타임 스탬프 파생 문자열로 임의의 문자열을 앞에 추가 해야할지 모르겠습니다. 또한 RNGCryptoServiceProvider
monty

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는 내부적으로 랜덤을 사용합니다. 그래서 이것은 여전히 ​​무작위를 사용하고 있습니다.
웨지

2

WinRT (Windows Store 앱)를위한 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
한 줄은 어때? Console.WriteLine ($ "랜덤 문자열 : {Path.GetRandomFileName (). Replace (". "," ")}"); 한 줄입니다.
PmanAce

1

나는 이것이 암호 적으로 어떻게 들리는 지 모르겠지만, 훨씬 복잡한 솔루션보다 훨씬 읽기 쉽고 간결하며 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직접 결과를 사용하는 대신 인덱스를 증가시키는 요점은 무엇입니까 ? 코드를 복잡하게 만들고 유용한 것을 얻지 못합니다.
코드 InChaos

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

이것을 간단하게 만드는 멋진 누겟 패키지 중 하나가 있습니다 .

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

좋은 예 중 하나가 여기 있습니다 .


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

왜 답장을 하시겠습니까? 이 질문에 대한 답변이 여러 차례 접수되었지만 여전히 반 답변 답변을 게시 할 수 있습니다.
Laurent
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.