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


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실제로 빠르게, 때로는 ForLoop및 GenerateRandomString리드에 누가 전환합니다.

  • 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.