Я б хотів генерувати випадкові унікальні рядки, наприклад ті, що створюються бібліотекою MSDN (наприклад, об’єкт помилки ). Слід створити рядок типу "t9zk6eay".
Я б хотів генерувати випадкові унікальні рядки, наприклад ті, що створюються бібліотекою MSDN (наприклад, об’єкт помилки ). Слід створити рядок типу "t9zk6eay".
Відповіді:
Використання Guid було б досить хорошим способом, але щоб отримати щось схоже на ваш приклад, ви, ймовірно, хочете перетворити його на рядок Base64:
Guid g = Guid.NewGuid();
string GuidString = Convert.ToBase64String(g.ToByteArray());
GuidString = GuidString.Replace("=","");
GuidString = GuidString.Replace("+","");
Я позбавляюся від "=" та "+", щоб трохи наблизитись до вашого прикладу, інакше ви отримуєте "==" у кінці вашого рядка та "+" в середині. Ось приклад вихідного рядка:
"OZVV5TpP4U6wJthaCORZEQ"
Convert.ToBase64Stringйдеться, подивіться тут .
new Guid()без "злому" (підробка годинника або внутрішня структура даних Windows). Сміливо використовуйте стільки ядер, ниток, примітивів для синхронізації тощо.
Оновлення 2016/1/23
Якщо ви вважаєте, що ця відповідь є корисною, вас може зацікавити проста бібліотека створення паролів (~ 500 SLOC), яку я опублікував :
Install-Package MlkPwgen
Тоді ви можете генерувати випадкові рядки так само, як у відповіді нижче:
var str = PasswordGenerator.Generate(length: 10, allowed: Sets.Alphanumerics);
Однією з переваг бібліотеки є те, що код краще враховується, щоб ви могли використовувати захищені випадковість для більш ніж генерування рядків . Перегляньте сайт проекту для отримання більш детальної інформації.
Оскільки ще ніхто не надав захищений код, я публікую наступне, якщо хтось вважає це корисним.
string RandomString(int length, string allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") {
if (length < 0) throw new ArgumentOutOfRangeException("length", "length cannot be less than zero.");
if (string.IsNullOrEmpty(allowedChars)) throw new ArgumentException("allowedChars may not be empty.");
const int byteSize = 0x100;
var allowedCharSet = new HashSet<char>(allowedChars).ToArray();
if (byteSize < allowedCharSet.Length) throw new ArgumentException(String.Format("allowedChars may contain no more than {0} characters.", byteSize));
// Guid.NewGuid and System.Random are not particularly random. By using a
// cryptographically-secure random number generator, the caller is always
// protected, regardless of use.
using (var rng = System.Security.Cryptography.RandomNumberGenerator.Create()) {
var result = new StringBuilder();
var buf = new byte[128];
while (result.Length < length) {
rng.GetBytes(buf);
for (var i = 0; i < buf.Length && result.Length < length; ++i) {
// Divide the byte into allowedCharSet-sized groups. If the
// random value falls into the last group and the last group is
// too small to choose from the entire allowedCharSet, ignore
// the value in order to avoid biasing the result.
var outOfRangeStart = byteSize - (byteSize % allowedCharSet.Length);
if (outOfRangeStart <= buf[i]) continue;
result.Append(allowedCharSet[buf[i] % allowedCharSet.Length]);
}
}
return result.ToString();
}
}
Дякуємо Ахмеду за те, що він вказав, як отримати код, що працює над .NET Core.
.netcore: Замінити var rng = new RNGCryptoServiceProvider()наvar rng = RandomNumberGenerator.Create()
Я застережу, що GUID не є випадковими числами . Вони не повинні використовуватися як основа для створення всього, що, як ви очікуєте, буде абсолютно випадковим (див. Http://en.wikipedia.org/wiki/Globally_Unique_Identifier ):
Криптоаналіз генератора WinAPI GUID показує, що, оскільки послідовність V4 GUID є псевдовипадковими, з огляду на початковий стан можна передбачити до наступних 250 000 GUID, повернених функцією UuidCreate. Ось чому GUID не слід використовувати в криптографії, наприклад, як випадкові ключі.
Замість цього просто використовуйте метод C # Random. Щось подібне ( код знайдено тут ):
private string RandomString(int size)
{
StringBuilder builder = new StringBuilder();
Random random = new Random();
char ch ;
for(int i=0; i<size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65))) ;
builder.Append(ch);
}
return builder.ToString();
}
GUID - це добре, якщо ви хочете щось унікальне (наприклад, унікальне ім’я файлу або ключ у базі даних), але вони не дуже зручні для того, що ви хочете бути випадковим (наприклад, пароль або ключ шифрування). Тож це залежить від вашої заявки.
Редагувати . Microsoft каже, що Random також не такий великий ( http://msdn.microsoft.com/en-us/library/system.random(VS.71).aspx ):
Для створення криптографічно захищеного випадкового числа, придатного для створення випадкового пароля, наприклад, використовуйте клас, похідний від System.Security.Cryptography.RandomNumberGenerator, такий як System.Security.Cryptography.RNGCryptoServiceProvider.
Я спростив рішення @Michael Kropats і зробив версію LINQ-esque.
string RandomString(int length, string alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
{
var outOfRange = byte.MaxValue + 1 - (byte.MaxValue + 1) % alphabet.Length;
return string.Concat(
Enumerable
.Repeat(0, int.MaxValue)
.Select(e => RandomByte())
.Where(randomByte => randomByte < outOfRange)
.Take(length)
.Select(randomByte => alphabet[randomByte % alphabet.Length])
);
}
byte RandomByte()
{
using (var randomizationProvider = new RNGCryptoServiceProvider())
{
var randomBytes = new byte[1];
randomizationProvider.GetBytes(randomBytes);
return randomBytes.Single();
}
}
Я не думаю, що вони насправді випадкові, але я здогадуюсь, що це деякі хеші.
Кожен раз, коли мені потрібен якийсь випадковий ідентифікатор, я зазвичай використовую GUID і перетворюю його на його "голе" представлення:
Guid.NewGuid().ToString("n");
Я здивований, чому не існує рішення CrytpoGraphic. GUID є унікальним, але не криптографічно безпечним . Дивіться цю скрипку Dotnet.
var bytes = new byte[40]; // byte size
using (var crypto = new RNGCryptoServiceProvider())
crypto.GetBytes(bytes);
var base64 = Convert.ToBase64String(bytes);
Console.WriteLine(base64);
Якщо ви хочете доповнити інструкцію:
var result = Guid.NewGuid().ToString("N") + base64;
Console.WriteLine(result);
Чистіший буквено-цифровий рядок:
result = Regex.Replace(result,"[^A-Za-z0-9]","");
Console.WriteLine(result);
Рішення Майкла Кропаца у VB.net
Private Function RandomString(ByVal length As Integer, Optional ByVal allowedChars As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") As String
If length < 0 Then Throw New ArgumentOutOfRangeException("length", "length cannot be less than zero.")
If String.IsNullOrEmpty(allowedChars) Then Throw New ArgumentException("allowedChars may not be empty.")
Dim byteSize As Integer = 256
Dim hash As HashSet(Of Char) = New HashSet(Of Char)(allowedChars)
'Dim hash As HashSet(Of String) = New HashSet(Of String)(allowedChars)
Dim allowedCharSet() = hash.ToArray
If byteSize < allowedCharSet.Length Then Throw New ArgumentException(String.Format("allowedChars may contain no more than {0} characters.", byteSize))
' Guid.NewGuid and System.Random are not particularly random. By using a
' cryptographically-secure random number generator, the caller is always
' protected, regardless of use.
Dim rng = New System.Security.Cryptography.RNGCryptoServiceProvider()
Dim result = New System.Text.StringBuilder()
Dim buf = New Byte(128) {}
While result.Length < length
rng.GetBytes(buf)
Dim i
For i = 0 To buf.Length - 1 Step +1
If result.Length >= length Then Exit For
' Divide the byte into allowedCharSet-sized groups. If the
' random value falls into the last group and the last group is
' too small to choose from the entire allowedCharSet, ignore
' the value in order to avoid biasing the result.
Dim outOfRangeStart = byteSize - (byteSize Mod allowedCharSet.Length)
If outOfRangeStart <= buf(i) Then
Continue For
End If
result.Append(allowedCharSet(buf(i) Mod allowedCharSet.Length))
Next
End While
Return result.ToString()
End Function
Про це запитували різні мови. Ось одне питання щодо паролів, які також повинні бути застосовані і тут.
Якщо ви хочете використовувати рядки для скорочення URL-адрес, вам також знадобиться словник <> або перевірка бази даних, щоб побачити, чи вже використаний згенерований ідентифікатор.
Якщо ви хочете буквено-цифрові рядки з малі та великі літери ([a-zA-Z0-9]), ви можете використовувати Convert.ToBase64String () для швидкого та простого рішення.
Що стосується унікальності, перегляньте проблему з днем народження, щоб обчислити, наскільки ймовірне зіткнення (A) довжина створених рядків та (B) кількість створених рядків.
Random random = new Random();
int outputLength = 10;
int byteLength = (int)Math.Ceiling(3f / 4f * outputLength); // Base64 uses 4 characters for every 3 bytes of data; so in random bytes we need only 3/4 of the desired length
byte[] randomBytes = new byte[byteLength];
string output;
do
{
random.NextBytes(randomBytes); // Fill bytes with random data
output = Convert.ToBase64String(randomBytes); // Convert to base64
output = output.Substring(0, outputLength); // Truncate any superfluous characters and/or padding
} while (output.Contains('/') || output.Contains('+')); // Repeat if we contain non-alphanumeric characters (~25% chance if length=10; ~50% chance if length=20; ~35% chance if length=32)
Отримайте унікальний ключ, використовуючи хеш-код GUID
public static string GetUniqueKey(int length)
{
string guidResult = string.Empty;
while (guidResult.Length < length)
{
// Get the GUID.
guidResult += Guid.NewGuid().ToString().GetHashCode().ToString("x");
}
// Make sure length is valid.
if (length <= 0 || length > guidResult.Length)
throw new ArgumentException("Length must be between 1 and " + guidResult.Length);
// Return the first length bytes.
return guidResult.Substring(0, length);
}
string randoms = Guid.NewGuid().ToString().Replace("-", string.Empty).Replace("+", string.Empty).Substring(0, 4);більше можна знайти тут