Случайную строку поколение


Я использую это в C# функция для генерации случайных купонов для системы. Как я могу улучшить его?

public static string GenerateCoupon(int length)
{
    string result = string.Empty;
    Random random = new Random((int)DateTime.Now.Ticks);
    List<string> characters = new List<string>() { };
    for (int i = 48; i < 58; i++)
    {
        characters.Add(((char)i).ToString());
    }
    for (int i = 65; i < 91; i++)
    {
        characters.Add(((char)i).ToString());
    }
    for (int i = 97; i < 123; i++)
    {
        characters.Add(((char)i).ToString());
    }
    for (int i = 0; i < length; i++)
    {
        result += characters[random.Next(0, characters.Count)];
        Thread.Sleep(1);
    }
    return result;
}

Бизнес-требования:

  1. Длина купоны не являются фиксированными и статичными
  2. Купоны могут содержать-Z, от A-Z и 0-9 (регистр буквенно-цифровой)
  3. Купоны должны быть уникальны (это значит, что мы храним их в качестве ключа в таблице в базе данных, и по каждому купону, мы проверяем его уникальность)


57604
23
задан 12 ноября 2011 в 09:11 Источник Поделиться
Комментарии
7 ответов

Давайте посмотрим на некоторые код:

Random random = new Random((int)DateTime.Now.Ticks);

Вам не нужно, чтобы создать затравку для случайных конструктор из часы, конструктор без параметров это:

Random random = new Random();


List<string> characters = new List<string>() { };

Вам не нужно для инициализации тестов скобки, когда вы не ставьте какие-либо предметы в списке в этой точке:

List<string> characters = new List<string>();


result += characters[random.Next(0, characters.Count)];

Используя += для конкатенации строк-это плохая практика. Струны не дописываются в конце, как строки являются неизменными. Код вида Х += У; на самом деле, так как Х = строку.Функция concat(Х, Y). Вы должны скорее использовать то StringBuilder для построения строки.


Thread.Sleep(1);

Почему на земле ты спишь в середине цикла?


Вместо создания списка строк, просто использовать строковый литерал, чтобы выбрать персонажей:

public static string GenerateCoupon(int length) {
Random random = new Random();
string characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
StringBuilder result = new StringBuilder(length);
for (int i = 0; i < length; i++) {
result.Append(characters[random.Next(characters.Length)]);
}
return result.ToString();
}

Если рассмотреть все эти символы должны быть включены, или ли вы должны исключить похожие символы, такие как о, О и 0. Наличие символов в строковый литерал позволяет легко сделать это.

Редактировать:

Если вы собираетесь вызвать метод несколько раз, то вы должны послать в генератор случайных чисел в качестве параметра:

public static string GenerateCoupon(int length, Random random) {
string characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
StringBuilder result = new StringBuilder(length);
for (int i = 0; i < length; i++) {
result.Append(characters[random.Next(characters.Length)]);
}
return result.ToString();
}

Использование:

Random rnd = new Random();
string[] coupon = new string[10];
for (int i = 0; i < coupon.Length; i++) {
coupon[i] = GenerateCoupon(10, rnd);
}
Console.WriteLine(String.Join(Environment.NewLine,coupon));

Пример вывода:

LHUSer9dPZ
btK0S01yLb
hruw4IXINJ
hwMdRDRujt
cr4TDezvcZ
b8tVETNXNL
JrG6sfXgZF
Y7FRypnRiQ
JbfnhY3qOx
quWNakbybY

31
ответ дан 12 ноября 2011 в 10:11 Источник Поделиться

Вы не должны использовать случайных для генерации купонов. Ваши купоны будут вполне предсказуемы: если кто-то может увидеть несколько купонов (особенно несколько подряд купоны), они смогут восстановить семя и создать все купоны. Случайная хорош для большинства численных расчетов и для некоторых игр, это совсем не хорошо, когда вы должны генерировать непредсказуемые значения. Действуют купоны, как пароли, необходимо криптографического качества случайности. К счастью, есть крипто-качества генератор случайных чисел в C# библиотека: система.Безопасности.Тайнописи.RNGCryptoServiceProvider.

Этот ГСЧ возвращает байт. Есть 256 возможных значений байта. Купоны можно использовать только один из 62 символов, поэтому вы должны отклонить байтов, которые не отображаются в ASCII буквы или цифры.

Кроме того, вы должны использовать то StringBuilder при построении строки чанк чанк. Решить ее в строку, когда вы закончили его строить.

StringBuilder coupon = new StringBuilder();
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] rnd = new byte[1];
int n = 0;
while (n < coupon.Length) {
rng.GetBytes(rnd);
char c = (char)rnd[0];
if ((Char.IsDigit(c) || Char.IsLetter(c)) && rnd[0] < 127) {
++n;
coupon.Append(rnd[0]);
}
}
return coupon.ToString();

Вы можете сделать поколения примерно в 4 раза быстрее, отвергнув меньшее количество значений. Вместо того чтобы принять только 62 значения, которые соответствуют символы, которые вы хотите, разделите на 4, чтобы получить одно из 64 значений равновероятны, и принять 62 из них (отображения их на правильные символы) и отклонить 2.

while (n < coupon.Length) {
rng.GetBytes(rnd);
rnd[0] %= 64;
if (rnd[0] < 62) {
++n;
coupon.Append((byte)((rnd[0] <= 9 ? '0' : rnd[0] <= 35 ? 'A' - 10 : 'a' - 36) + rnd[0]);
}
}

17
ответ дан 14 ноября 2011 в 12:11 Источник Поделиться

Некая общая идея, я надеюсь, что все работы в C# тоже. Не стесняйтесь редактировать ответ, если это не правильный синтаксис c#.

1, Изменить тип символов списка чар и изменять переменную цикла в Чаре тоже. Таким образом, вы не должны бросить, а для петель легче читать:

List<char> characters = new List<char>() { };
for (char c = '0'; i <= '9'; c++) {
characters.Add(c);
}
...
for (int i = 0; i < length; i++){
result += characters[random.Next(0, characters.Count)];
}

2, есть ли основания для резьбы.Сна(1);. Это выглядит ненужным.

3, я бы удалить 0, О, О И Л, 1 из списка. Можно легко перепутать их.

4, я вытаскиваю AllowedCharacters способ:

public static List<char> AllowedCharacters() {
List<char> characters = new List<char>() { };
for (char c = '0'; i <= '9'; c++) {
characters.Add(c);
}
...
characters.Remove('O');
characters.Remove('0');
...
return characters;
}

public static string GenerateCoupon(int length)
{
string result = string.Empty;
Random random = new Random((int)DateTime.Now.Ticks);
List<string> characters = AllowedCharacters();

for (int i = 0; i < length; i++) {
result += characters[random.Next(0, characters.Count)];
}
return result;
}

5
ответ дан 12 ноября 2011 в 01:11 Источник Поделиться

вот код, который я буду выполнять. Его намного быстрее и проще

public static string GenerateCoupon(int length) 
{
return Guid.NewGuid().ToString().Replace("-", string.Empty).Substring(0, 10);
}

Используя гильдии gaurantees уникальность, так что ваши скидочные коды не пересекаются.

4
ответ дан 16 ноября 2011 в 04:11 Источник Поделиться

Если это приемлемо, чтобы иметь немного длиннее строки, вы могли бы использовать ShortGuid класс. Это принимает GUID и делает его немного более читабельным, чем формат 32 байта ты привык ({ххх-ххх-ххх...}).

Пример автора:


c9a646d3-9c61-4cb7-bfcd-ee2522c8f633}

укоротить до:


00amyWGct0y_ze4lIsj2Mw

Это может быть немного слишком долго для кода купона. Одно другое предложение заключается в использовании произносимых генератор паролей, ссылка что-то конвертировать из Java источник некоторое время назад. Некоторые капитализированных примеры:


COLINITABO
OWNSATLEDG
GORGIRRUGO
NOCKAYWIVI
FAWGILLIOL

4
ответ дан 28 ноября 2011 в 06:11 Источник Поделиться

Что Нить.Сна(1) является реальной проблемой, особенно если вы собираетесь использовать это, чтобы генерировать тысячи или миллионы купонов за один раз. Единственная причина, почему вы нуждаетесь в этом, потому что вы создаете новый экземпляр случайный для каждого купона и заполнения этого экземпляра с текущим временем. Конструктор по умолчанию для случайных уже обрабатывает на основе времени заполнения; если вы делаете экземпляр статического, вам нужно только построить ее один раз и тем самым избежать дублирования вопроса.

Мне нравится @palacsint идея использования списка для хранения разрешенных символов и заполнения его характер-индексированный для петли, хотя я бы в список отложенной инициализации собственность, а не воссоздавать его каждый раз. И я полностью согласен с @Guffa точки о с помощью класса StringBuilder , чтобы создать купон, а не += оператора.

public class CouponGenerator
{
private static List<char> _allowed = null;
private static List<char> AllowedChars
{
get
{
if (_allowed == null)
{
_allowed = new List<char>();
for (char c = 'A'; c < 'Z'; c++)
{
_allowed.Add(c);
}
for (char c = 'a'; c < 'z'; c++)
{
_allowed.Add(c);
}
for (char c = '0'; c < '9'; c++)
{
_allowed.Add(c);
}
}
return _allowed;
}
}
private static Random _rg = new Random();
public static string GenerateCoupon(int length)
{
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++)
{
sb.Append(AllowedChars[_rg.Next(0, AllowedChars.Count)]);
}
return sb.ToString();
}
}

2
ответ дан 13 ноября 2011 в 07:11 Источник Поделиться

Другой способ сделать это:

    public static string CouponGenerator(int length)
{
var sb = new StringBuilder();
for (var i = 0; i < length; i++)
{
var ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * _random.NextDouble() + 65)));
sb.Append(ch);
}

return sb.ToString();
}
private static readonly Random _random = new Random();

1
ответ дан 14 ноября 2011 в 01:11 Источник Поделиться