Ruby 数组元素

Ruby Array Elements

我正在尝试在 ruby 中创建密码生成。目前一切正常,只是卡在了生成密码的最后一步。

我问用户 he/she 是否希望密码包含数字、小写或大写。 如果是,用户将为否输入 1 和 0。

如果一切都是 1,我使用下面的代码生成密码。这意味着用户想要包括数字,小写和大写。

 if numbers == 1 && lowercase == 1 && uppercase == 1
     passGen = [(0..9).to_a + ('A'..'Z').to_a + ('a'..'z').to_a].flatten.sample(10)
 end

 p passGen

这在 90% 的时间都有效。 10% 的情况下,生成的密码不会包含任何数字。但其他一切都存在。我不确定这是否是因为从中采样密码的数组的大小或长度。

不管怎样,让我们​​进入下面的主要问题

问题出在这里,如果一个或多个输入为 0,我很难编写生成密码的代码。那是因为用户不想包含数字。或者没有数字和大写等。因为我无法预测用户可能想要或不想要什么。我需要这方面的帮助。 谢谢。

您需要使输入数组更加动态:

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(&: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) }

代码不知道它需要包含来自每个组的 digit/letter。该样本采用随机符号,并且由于您基本上是抽样 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)

通过说 (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]/) && passGen.match(/[a-z]/) && passGen.match(/\d/)
  passGen = generate_password_with_digits_and_caps
end

这也可以工作(更接近您的代码段):

if numbers == 1 && lowercase == 1 && uppercase == 1
  passGen = ''
     
  until passGen.match(/[A-Z]/) && passGen.match(/[a-z]/) && passGen.match(/\d/)
    passGen = [(0..9).to_a + ('A'..'Z').to_a + ('a'..'z').to_a].flatten.sample(10).join
  end
end

从一些简单而愚蠢的事情开始:

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.

因为这超出了你的提问范围,我也不知道你想不想问到这里,这里就不多说了。