#arrays #ruby #ruby-on-rails-3
Вопрос:
Я пытаюсь создать генератор паролей в ruby. На данный момент все работает, просто застрял на последнем этапе генерации пароля.
Я спросил пользователя, хотел бы он/она, чтобы пароль включал цифры, строчные или прописные. Если ДА, пользователь введет 1 и 0 вместо «НЕТ».
Я использовал приведенный ниже код для генерации пароля, если все равно 1. Это означает, что пользователь хочет включить цифры, строчные и прописные.
if numbers == 1 amp;amp; lowercase == 1 amp;amp; uppercase == 1
passGen = [(0..9).to_a ('A'..'Z').to_a ('a'..'z').to_a].flatten.sample(10)
end
p passGen
Это работает в 90% случаев. В 10% случаев сгенерированный пароль не будет содержать никаких цифр. Но все остальное присутствует. Я не уверен, связано ли это с размером или длиной массива, из которого берется пароль.
В любом случае давайте перейдем к основной проблеме ниже
Вот в чем проблема, я изо всех сил пытаюсь написать код для генерации пароля, если один или несколько входных данных равны 0. Это если пользователь не хочет включать номера. Или без цифр и прописных букв и т. Д. Поскольку я не могу предсказать, что пользователь может хотеть или не хотеть. Мне нужна помощь в этом, пожалуйста. Спасибо.
Комментарии:
1. Почему вы используете версию Rails, которая не поддерживалась годами и имеет множество незащищенных уязвимостей в системе безопасности? И вообще, какое это имеет отношение к рельсам?
Ответ №1:
Вам нужно будет сделать свой входной массив более динамичным:
passGen = []
passGen = (0..9).to_a if numbers == 1
passGen = ('A'..'Z').to_a if uppercase == 1
passGen = ('a'..'z').to_a if lowercase == 1
passGen.sample(10).join
Теперь, чтобы решить вашу другую проблему с отсутствующими символами — это вызвано тем, что вы просто берете 10 случайных символов из массива. Так что он может просто взять, например, все цифры.
Чтобы решить эту проблему, вам нужно сначала получить один символ из каждого генератора, а затем случайным образом сгенерировать оставшиеся символы и перетасовать результат:
def generators(numbers:, lowercase:, uppercase:)
[
(0..9 if numbers),
('A'..'Z' if uppercase),
('a'..'z' if lowercase)
].compact.map(amp;:to_a)
end
def generate_password(generators:, length:, min_per_generator: 1)
chars = generators.flat_map {|g| Array.new(min_per_generator) { g.sample }}
chars = Array.new(length - chars.length) { generators.sample.sample }
chars.shuffle.join
end
gens = generators(numbers: numbers == 1, uppercase == 1, lowercase: lowercase == 1)
Array.new(10) { generate_password(generators: gens, length: 10) }
Комментарии:
1. Это не решает рассматриваемую проблему, пожалуйста, прочитайте, о чем он спрашивает
2. Это вызовет ту же проблему
3. @Vulwsztyn Главная проблема заключается в следующем:
I am struggling to write the code to generate password if one or more of input is 0. That's if user don't want to include numbers.
Пожалуйста, прочитайте весь вопрос целиком.4. спасибо за ваш вклад. таким образом, ваше решение решило первую проблему.
5. @Homer — Обновленный ответ с немного более общим решением обеих проблем.
Ответ №2:
Код не знает, что он должен включать цифру/букву из каждой группы. В выборке используются случайные знаки, и, поскольку вы в основном производите выборку 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
, существует вероятность того, что все знаки не будут цифрами.
Самый простой способ исправить это-проверить, есть ли знак из каждой группы в «пароле», а затем заменить случайный знак знаком из группы, которого нет.
Если бы я должен был запрограммировать это, я бы сделал это так
def random_from_range(range)
range.to_a.sample.to_s
end
def passGen(numbers, lowercase, uppercase)
result = ''
possibleSigns = []
if numbers == 1
range = (0..9)
result = random_from_range(range)
possibleSigns = range.to_a
end
if lowercase == 1
range = ('A'..'Z')
result = random_from_range(range)
possibleSigns = range.to_a
end
if uppercase == 1
range = ('a'..'z')
result = random_from_range(range)
possibleSigns = range.to_a
end
desired_lenth = 10
while result.length < desired_lenth
result = possibleSigns.sample.to_s
end
result
end
puts passGen(1,1,1)
Комментарии:
1. Пожалуйста, прочитайте весь вопрос целиком — сам вопрос находится в последнем абзаце:
I am struggling to write the code to generate password if one or more of input is 0.
2. да, да, Ик, отредактировано, чтобы включить мой ответ
3. Огромное спасибо. Ваше решение ответило на оба вопроса. Благодарю
4. Минор:
sample(1)[0]
это простоsample
Ответ №3:
Говоря (0..9).to_a ('A'..'Z').to_a ('a'..'z').to_a
, вы создаете массив 10 26 26 = 62 элемента, а затем вы выбираете из них только 10 элементов.
На вашем месте я бы обернул генерацию пароля вокруг until
блока:
def generate_password_with_digits_and_caps
[(0..9).to_a ('A'..'Z').to_a ('a'..'z').to_a].flatten.sample(10).join
end
passGen = ''
until passGen.match(/[A-Z]/) amp;amp; passGen.match(/[a-z]/) amp;amp; passGen.match(/d/)
passGen = generate_password_with_digits_and_caps
end
Это также может сработать (ближе к вашему фрагменту):
if numbers == 1 amp;amp; lowercase == 1 amp;amp; uppercase == 1
passGen = ''
until passGen.match(/[A-Z]/) amp;amp; passGen.match(/[a-z]/) amp;amp; passGen.match(/d/)
passGen = [(0..9).to_a ('A'..'Z').to_a ('a'..'z').to_a].flatten.sample(10).join
end
end
Комментарии:
1. Пожалуйста, прочитайте весь вопрос целиком — сам вопрос находится в последнем абзаце:
I am struggling to write the code to generate password if one or more of input is 0.
2. Я поделился идеей, которая, возможно, не самая лучшая, но довольно простая в реализации
3. Спасибо за ваш вклад, чрезвычайно полезный. Это решает первую часть вопроса. Я просто не знал, что существует много способов решения этой проблемы. Спасибо
Ответ №4:
Начните с чего-нибудь простого и глупого:
passGen = (('0'..'9').to_a.sample(1) ('A'..'Z').to_a.sample(1) ('a'..'z').to_a.sample(8).shuffle).join
Технически говоря, это уже соответствует вашим требованиям. С точки зрения эстетики и безопасности недостатком здесь является то, что количество символов верхнего регистра всегда равно 8. Более элегантным решением было бы найти три ненулевых целых числа, которые в сумме дают 10 и могут быть использованы в качестве аргументов для sample
вызова. Кроме того, если номера не запрашиваются, вы просто передаете 0
их в качестве аргумента sample
.
Поскольку это выходит за рамки вашего вопроса, и я даже не знаю, хотите ли вы зайти так далеко, я не буду подробно останавливаться на этом здесь далее.
Комментарии:
1. Спасибо за вклад. Длина пароля будет устанавливаться пользователем, я дал 10 для простоты. Поиск трех ненулевых целых чисел, которые в сумме дают неизвестную длину, может оказаться непростым подходом для новичка. Кроме того, я не уверен, что «перетасовка» в вашем коде работает хорошо, поскольку вывод начинается с цифры и заглавной буквы, так же, как позиция для цифр и заглавной буквы в коде. Я не вижу, чтобы он перетасовывался. Простите меня, если я ошибаюсь.
2. Чтобы добавить к этому — разбиение числа на несколько частей также было моим первым подходом, но это намного сложнее, чем кажется, особенно если вы хотите сохранить равные вероятности таких разбиений. Например, разбиение 10 на 3 части: если вы наивно просто начнете с того, что возьмете случайное число от 1 до 8, то у вас будет чуть более 1/8 вероятности разделения [8, 1, 1] и только 1/15, чтобы получить [4,3,3] (в любом порядке).
3. Это правильно, но вы ничего не указали в своем вопросе. Вы также не указали, какими свойствами (равными вероятностями и т.д.) Должны обладать желаемые числа. По крайней мере, разбиение общего числа на подходящие случайные партии чисел само по себе является проблемой, и если вы хотите обсудить это, вам все равно следует открыть новый вопрос. В Stackoverflow политика заключается в том, что один вопрос должен быть сосредоточен на одной проблеме.