임의의 영숫자 노드를 생성해야합니까?
C #에서 임의의 8 자 영숫자를 생성해야합니까?
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
강력한 난수 생성기가 필요한 경우 클래스를 사용하십시오 .)
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
강력한 난수 생성기가 필요한 경우 클래스를 사용하십시오 .)
댓글에 따라 업데이트되었습니다. 원래 구현은 시간의 ~ 1.95 %를 생성하고 나머지 문자는 시간의 ~ 1.56 %를 생성했습니다. 업데이트는 모든 문자를 ~ 1.61 % 생성합니다.
프레임 워크 지원 -.NET Core 3 (및 .NET Standard 2.1 이상을 지원하는 플랫폼)은 원하는 범위 내에서 임의의 정수를 임의의 정수를 위해 암호화 된 사운드 메서드 RandomNumberGenerator.GetInt32 () 를 생성 합니다 .
제시된 일부 대안과 달리 이것은 암호 학적으로 건전 합니다.
using System;
using System.Security.Cryptography;
using System.Text;
namespace UniqueKey
{
public class KeyGenerator
{
internal static readonly char[] chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
public static string GetUniqueKey(int size)
{
byte[] data = new byte[4*size];
using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
{
crypto.GetBytes(data);
}
StringBuilder result = new StringBuilder(size);
for (int i = 0; i < size; i++)
{
var rnd = BitConverter.ToUInt32(data, i * 4);
var idx = rnd % chars.Length;
result.Append(chars[idx]);
}
return result.ToString();
}
public static string GetUniqueKeyOriginal_BIASED(int size)
{
char[] chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".ToCharArray();
byte[] data = new byte[size];
using (RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider())
{
crypto.GetBytes(data);
}
StringBuilder result = new StringBuilder(size);
foreach (byte b in data)
{
result.Append(chars[b % (chars.Length)]);
}
return result.ToString();
}
}
}
여기 에있는 대안에 대한 논의를 기반으로하고 아래 설명에 따라 업데이트 / 수정했습니다.
다음은 이전 및 업데이트 된 출력의 문자를 사용하고 작은 테스트 도구입니다. 무작위성 분석에 대한 자세한 내용은 random.org를 확인하십시오.
using System;
using System.Collections.Generic;
using System.Linq;
using UniqueKey;
namespace CryptoRNGDemo
{
class Program
{
const int REPETITIONS = 1000000;
const int KEY_SIZE = 32;
static void Main(string[] args)
{
Console.WriteLine("Original BIASED implementation");
PerformTest(REPETITIONS, KEY_SIZE, KeyGenerator.GetUniqueKeyOriginal_BIASED);
Console.WriteLine("Updated implementation");
PerformTest(REPETITIONS, KEY_SIZE, KeyGenerator.GetUniqueKey);
Console.ReadKey();
}
static void PerformTest(int repetitions, int keySize, Func<int, string> generator)
{
Dictionary<char, int> counts = new Dictionary<char, int>();
foreach (var ch in UniqueKey.KeyGenerator.chars) counts.Add(ch, 0);
for (int i = 0; i < REPETITIONS; i++)
{
var key = generator(KEY_SIZE);
foreach (var ch in key) counts[ch]++;
}
int totalChars = counts.Values.Sum();
foreach (var ch in UniqueKey.KeyGenerator.chars)
{
Console.WriteLine($"{ch}: {(100.0 * counts[ch] / totalChars).ToString("#.000")}%");
}
}
}
}
솔루션 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 번 반복하여 테스트하여 하나의 이메일을 생성했습니다.
다음은 Dot Net Perls의 Sam Allen 예제에서 훔친 예제입니다.
8 자만 필요한 경우 System.IO 네임 스페이스에서 Path.GetRandomFileName ()을 사용합니다. Sam은 "여기서 Path.GetRandomFileName 메서드를 사용하면 더 나은 임의성을 위해 RNGCryptoServiceProvider를 사용하기 때문에 더 우수합니다. 그러나 11 개의 임의 문자로 제한됩니다."
GetRandomFileName은 항상 9 번째 문자에 마침표가있는 12자를 반환합니다. 따라서 마침표를 제거하고 (무작위가 아니기 때문에) 꾸러미에서 8을 가져와야합니다. 사실, 당신은 처음 8 개의 문자 만 취하고 기간에 대해 걱정할 수 없습니다.
public string Get8CharacterRandomString()
{
string path = Path.GetRandomFileName();
path = path.Replace(".", ""); // Remove period.
return path.Substring(0, 8); // Return 8 character string
}
PS : 감사합니다 Sam
내 코드의 주요 목표는 다음과 가변적입니다.
- 모든 것이 좋습니다.
- 각 인수 세트에 대해보다 높은 수준의 높은 수준을 가지고 있습니다. PRNG가 20 억 (31 비트 엔트로피) 다른 값만 생성하는 경우 8 자 (~ 47 비트 엔트로피)를 생성하는 것은 의미가 없습니다.
- 사람들이 암호 나 다른 보안 토큰을 사용하기를 기대하기 때문에 안전합니다.
첫 번째 속성은 알파벳 크기의 모듈로 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);
}
가장 간단한 방법 :
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
인스턴스 에서 확장 메소드로 만들 수 있습니다.
이 메시지의 다양한 답변에 대한 성능 비교 :
방법 및 설정
// what's available
public static string possibleChars = "abcdefghijklmnopqrstuvwxyz";
// optimized (?) what's available
public static char[] possibleCharsArray = possibleChars.ToCharArray();
// optimized (precalculated) count
public static int possibleCharsAvailable = possibleChars.Length;
// shared randomization thingy
public static Random random = new Random();
// http://stackoverflow.com/a/1344242/1037948
public string LinqIsTheNewBlack(int num) {
return new string(
Enumerable.Repeat(possibleCharsArray, num)
.Select(s => s[random.Next(s.Length)])
.ToArray());
}
// http://stackoverflow.com/a/1344258/1037948
public string ForLoop(int num) {
var result = new char[num];
while(num-- > 0) {
result[num] = possibleCharsArray[random.Next(possibleCharsAvailable)];
}
return new string(result);
}
public string ForLoopNonOptimized(int num) {
var result = new char[num];
while(num-- > 0) {
result[num] = possibleChars[random.Next(possibleChars.Length)];
}
return new string(result);
}
public string Repeat(int num) {
return new string(new char[num].Select(o => possibleCharsArray[random.Next(possibleCharsAvailable)]).ToArray());
}
// http://stackoverflow.com/a/1518495/1037948
public string GenerateRandomString(int num) {
var rBytes = new byte[num];
random.NextBytes(rBytes);
var rName = new char[num];
while(num-- > 0)
rName[num] = possibleCharsArray[rBytes[num] % possibleCharsAvailable];
return new string(rName);
}
//SecureFastRandom - or SolidSwiftRandom
static string GenerateRandomString(int Length) //Configurable output string length
{
byte[] rBytes = new byte[Length];
char[] rName = new char[Length];
SolidSwiftRandom.GetNextBytesWithMax(rBytes, biasZone);
for (var i = 0; i < Length; i++)
{
rName[i] = charSet[rBytes[i] % charSet.Length];
}
return new string(rName);
}
결과
LinqPad에서 테스트되었습니다. 크기가 10 인 경우 다음을 생성합니다.
- Linq = chdgmevhcy [10]에서
- 루프에서 = gtnoaryhxr [10]
- 선택에서 = rsndbztyby [10]
- 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) 르 [다른 시스템]
한 줄의 코드 가 트릭을 수행합니다. :)Membership.GeneratePassword()
은 다음 동일한 데모 입니다.
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);
}
}
우리는 또한 사용자 정의 많은 것을 무작위로 사용하지만 구현 한 것은 약간의 단순화 된 유연성을 제공합니다.
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);
또 다른 옵션은 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());
질문 :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 :이 답변은 가장 유명한 짧은 답변은 질문과 답변을 분리 할 공간을 원했습니다. 내 대답의 목적은 환상 혁신적인 대답을 제공하는 것보다 마술 수준에 대해 경고하는 것입니다.
내 간단한 한 줄 코드가 나를 위해 작동합니다. :)
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);
}
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);
스타일 선호도는 다를 수 있습니다.
다른 답변을 검토하고 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 버튼을 클릭합니다.이 링크는 최신 버전이 아닌 특정 버전의 코드로 연결됩니다.)
업데이트 된 메모 :
- 다른 답변과 관련하여-출력 길이를 알고 있다면 StringBuilder가 필요하지 않습니다. ToCharArray를 사용할 때 배열을 만들 수 있습니다. (먼저 빈 배열을 만들 필요가 없습니다)
- 다른 답변과 관련하여-성능을 위해 한 번에 하나씩 얻는 대신 NextBytes를 사용합니다.
- 기술적으로 더 빠른 액세스를 위해 바이트 배열을 고정 할 수 있습니다. 일반적으로 바이트 배열에서 6-8 번 이상 반복 할 때 그만한 가치가 있습니다. (여기서 발생하지 않음)
- 최상의 임의성을 위해 RNGCryptoServiceProvider 사용
- 임의 데이터의 1MB 버퍼 캐싱 사용 -벤치마킹에 따르면 캐시 된 단일 바이트 액세스 속도가 ~ 1000 배 더 빠 사용합니다. 1MB에서 9ms가있는 반면 캐시되지 않은 경우 989ms가 존재합니다.
- 내 새 클래스 내 에서 바이어스 영역 거부를 최적화했습니다 .
질문에 대한 최종 솔루션 :
static char[] charSet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
static int byteSize = 256; //Labelling convenience
static int biasZone = byteSize - (byteSize % charSet.Length);
public string GenerateRandomString(int Length) //Configurable output string length
{
byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
char[] rName = new char[Length];
SecureFastRandom.GetNextBytesMax(rBytes, biasZone);
for (var i = 0; i < Length; i++)
{
rName[i] = charSet[rBytes[i] % charSet.Length];
}
return new string(rName);
}
그러나 당신은 나의 새로운 (예상되지 않은) 수업이 필요합니다.
/// <summary>
/// My benchmarking showed that for RNGCryptoServiceProvider:
/// 1. There is negligable benefit of sharing RNGCryptoServiceProvider object reference
/// 2. Initial GetBytes takes 2ms, and an initial read of 1MB takes 3ms (starting to rise, but still negligable)
/// 2. Cached is ~1000x faster for single byte at a time - taking 9ms over 1MB vs 989ms for uncached
/// </summary>
class SecureFastRandom
{
static byte[] byteCache = new byte[1000000]; //My benchmark showed that an initial read takes 2ms, and an initial read of this size takes 3ms (starting to raise)
static int lastPosition = 0;
static int remaining = 0;
/// <summary>
/// Static direct uncached access to the RNGCryptoServiceProvider GetBytes function
/// </summary>
/// <param name="buffer"></param>
public static void DirectGetBytes(byte[] buffer)
{
using (var r = new RNGCryptoServiceProvider())
{
r.GetBytes(buffer);
}
}
/// <summary>
/// Main expected method to be called by user. Underlying random data is cached from RNGCryptoServiceProvider for best performance
/// </summary>
/// <param name="buffer"></param>
public static void GetBytes(byte[] buffer)
{
if (buffer.Length > byteCache.Length)
{
DirectGetBytes(buffer);
return;
}
lock (byteCache)
{
if (buffer.Length > remaining)
{
DirectGetBytes(byteCache);
lastPosition = 0;
remaining = byteCache.Length;
}
Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
lastPosition += buffer.Length;
remaining -= buffer.Length;
}
}
/// <summary>
/// Return a single byte from the cache of random data.
/// </summary>
/// <returns></returns>
public static byte GetByte()
{
lock (byteCache)
{
return UnsafeGetByte();
}
}
/// <summary>
/// Shared with public GetByte and GetBytesWithMax, and not locked to reduce lock/unlocking in loops. Must be called within lock of byteCache.
/// </summary>
/// <returns></returns>
static byte UnsafeGetByte()
{
if (1 > remaining)
{
DirectGetBytes(byteCache);
lastPosition = 0;
remaining = byteCache.Length;
}
lastPosition++;
remaining--;
return byteCache[lastPosition - 1];
}
/// <summary>
/// Rejects bytes which are equal to or greater than max. This is useful for ensuring there is no bias when you are modulating with a non power of 2 number.
/// </summary>
/// <param name="buffer"></param>
/// <param name="max"></param>
public static void GetBytesWithMax(byte[] buffer, byte max)
{
if (buffer.Length > byteCache.Length / 2) //No point caching for larger sizes
{
DirectGetBytes(buffer);
lock (byteCache)
{
UnsafeCheckBytesMax(buffer, max);
}
}
else
{
lock (byteCache)
{
if (buffer.Length > remaining) //Recache if not enough remaining, discarding remaining - too much work to join two blocks
DirectGetBytes(byteCache);
Buffer.BlockCopy(byteCache, lastPosition, buffer, 0, buffer.Length);
lastPosition += buffer.Length;
remaining -= buffer.Length;
UnsafeCheckBytesMax(buffer, max);
}
}
}
/// <summary>
/// Checks buffer for bytes equal and above max. Must be called within lock of byteCache.
/// </summary>
/// <param name="buffer"></param>
/// <param name="max"></param>
static void UnsafeCheckBytesMax(byte[] buffer, byte max)
{
for (int i = 0; i < buffer.Length; i++)
{
while (buffer[i] >= max)
buffer[i] = UnsafeGetByte(); //Replace all bytes which are equal or above max
}
}
}
역사상-이 답변에 대한 이전 솔루션은 임의 개체를 사용했습니다.
private static char[] charSet =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray();
static rGen = new Random(); //Must share, because the clock seed only has Ticks (~10ms) resolution, yet lock has only 20-50ns delay.
static int byteSize = 256; //Labelling convenience
static int biasZone = byteSize - (byteSize % charSet.Length);
static bool SlightlyMoreSecurityNeeded = true; //Configuration - needs to be true, if more security is desired and if charSet.Length is not divisible by 2^X.
public string GenerateRandomString(int Length) //Configurable output string length
{
byte[] rBytes = new byte[Length]; //Do as much before and after lock as possible
char[] rName = new char[Length];
lock (rGen) //~20-50ns
{
rGen.NextBytes(rBytes);
for (int i = 0; i < Length; i++)
{
while (SlightlyMoreSecurityNeeded && rBytes[i] >= biasZone) //Secure against 1/5 increased bias of index[0-7] values against others. Note: Must exclude where it == biasZone (that is >=), otherwise there's still a bias on index 0.
rBytes[i] = rGen.NextByte();
rName[i] = charSet[rBytes[i] % charSet.Length];
}
}
return new string(rName);
}
공연 :
- SecureFastRandom - 최초의 단일 실행은 = ~ 9-33ms . 눈에 널리 지. 진행 중 : 10,000 회 이상 5ms (때는 최대 13ms까지 증가), 단일 평균 반복 = 1.5 마이크로 초. . 참고 : 일반적으로 2 회가 필요하지만 최대 8 회 캐시 고침이 필요합니다. 바이어스 영역을 초과하는 단일 바이트 수에 따라 증가합니다.
- 임의 - 첫 번째 단일 실행 = ~ 0-1ms . 눈에 널리 지. 진행 중 : 10,000 회 이상 5ms . 단일 평균 반복 = .5 마이크로 초. . 거의 같은 속도입니다.
또한 확인하십시오 :
- https://bitbucket.org/merarischroeder/number-range-with-no-bias/src
- https://stackoverflow.com/a/45118325/887092
대신 링크는 또 다른 접근 방식입니다. 이 새로운 코드베이스에 버퍼링을 추가 할 수 있습니다. 가장 중요한 것은 편견을 제거하고 속도와 장단점을 벤치마킹하는 다양한 접근 방식을 탐색하는 것이 었습니다.
끔찍하지만 알아요.하지만 스스로를 도울 수 없습니다.
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);
}
}
}
나는 무작위의 형식을 제어하고 싶은 더 구체적인 내용을보고 있습니다. 예를 들어 자동차의 번호판에는 특정 형식 (국가 별)이 있고 임의의 번호판을 만들고 싶었습니다.
나는 작성하기 위해 임의의 확장 방법을 작성하기로 결정했습니다. (이것은 다중 스레딩 시나리오에서 이중을 수 있으므로 임의 개체를 반복하기위한 것입니다). 요점 ( 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)];
}
}
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());
}
고유 한 부분 (시퀀스, 카운터 또는 날짜) 및 임의의 두 부분을 결합하십시오.
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 algoritm 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())
}
사용하지 않는 솔루션 Random
:
var chars = Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 8);
var randomStr = new string(chars.SelectMany(str => str)
.OrderBy(c => Guid.NewGuid())
.Take(8).ToArray());
다음은 WinRT (Windows Store App)에 대한 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();
}
이제 한 줄의 맛으로.
private string RandomName
{
get
{
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());
}
}
나는 최선의 방법이 아니라는 것을 압니다. 그러나 시도 할 수 있습니다.
string str = Path.GetRandomFileName(); //This method returns a random file name of 11 characters
str = str.Replace(".","");
Console.WriteLine("Random string: " + str);
이것이 암호 학적으로 얼마나 들리는지는 모르겠지만, 훨씬 복잡한 솔루션 (imo)보다 더 읽기 거의 간결하며 System.Random
기반 솔루션보다 "무작위"가 필요합니다 .
return alphabet
.OrderBy(c => Guid.NewGuid())
.Take(strLength)
.Aggregate(
new StringBuilder(),
(builder, c) => builder.Append(c))
.ToString();
이 버전 또는 다음 버전이 "더 예쁘다"고 생각하는지 여부는 없지만 똑같은 결과를 제공합니다.
return new string(alphabet
.OrderBy(o => Guid.NewGuid())
.Take(strLength)
.ToArray());
그것보다 훨씬 더 많은 것이 아니라 매초 수백만 개의 임의의 것들을 생성하는 것이 좋습니다.
참고 :이 솔루션은 알파벳에서 기호의 반복을 허용하지 않습니다. 그 방법은 일부 상황에서 덜 예측하며 모두 사용 사례에 따라.
md5 또는 sha1 해시를 계산 한 다음 원하는 길이로 사용할 수 있습니다.
또한 GUID를 생성하고자합니다.
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;
}
}
다음은 알파벳과 숫자를 정의하지 않고 임의의 영숫자 숫자 (암호와 테스트 데이터를 생성하는 데 사용함)를 생성하는 코드입니다.
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);
}
아주 간단한 해결책. ASCII 값을 사용 하고 그 사이에 "무작위"문자를 생성합니다.
public static class UsernameTools
{
public static string GenerateRandomUsername(int length = 10)
{
Random random = new Random();
StringBuilder sbuilder = new StringBuilder();
for (int x = 0; x < length; ++x)
{
sbuilder.Append((char)random.Next(33, 126));
}
return sbuilder.ToString();
}
}
당신은 단지 어셈블리를 사용합니다 SRVTextToImage
. 그리고 임의의 노드를 생성하는 코드를 아래에 작성하십시오.
CaptchaRandomImage c1 = new CaptchaRandomImage();
string text = c1.GetRandomString(8);
주로 Captcha를 구현하는 데 사용됩니다. 그러나 귀하의 경우에도 작동합니다. 도움이되기를 바랍니다.
참고 URL : https://stackoverflow.com/questions/1344221/how-can-i-generate-random-alphanumeric-strings
'ProgramingTip' 카테고리의 다른 글
JavaScript에서 정의되지 않은 변수를 확인하는 방법 (0) | 2020.09.28 |
---|---|
한 div를 다른 div 위에 기계하는 방법 (0) | 2020.09.28 |
Git : 로컬 브랜치 만 비용은 어떻게합니까? (0) | 2020.09.28 |
마스터 브랜치와 '원산지 / 마스터'가 갈라 졌는데 어떻게 브랜치를 '해제'할까요? (0) | 2020.09.28 |
한 git 브랜치에서 다른 브랜치로 단일 파일 버전을 비용 지불해야합니까? (0) | 2020.09.28 |