使用Ruby中的SecureRandom生成长度为6的随机数

7

我尝试了SecureRandom.random_number(9**6),但有时返回5位数字,有时返回6位数字。我希望它始终是6位长度。我也更喜欢它以SecureRandom.random_number(9**6)的格式呈现,而不使用6.times.map这样的语法,这样在我的控制器测试中更容易进行存根。


1
提示:9**6等于531441。 - tadman
4个回答

12

生成一个随机的六位字符串:

# This generates a 6-digit string, where the
# minimum possible value is "000000", and the
# maximum possible value is "999999"
SecureRandom.random_number(10**6).to_s.rjust(6, '0')

这里通过将单行代码拆分成多行并解释所使用的变量,提供了更详细的信息:

  # Calculate the upper bound for the random number generator
  # upper_bound = 1,000,000
  upper_bound = 10**6

  # n will be an integer with a minimum possible value of 0,
  # and a maximum possible value of 999,999
  n = SecureRandom.random_number(upper_bound)

  # Convert the integer n to a string
  # unpadded_str will be "0" if n == 0
  # unpadded_str will be "999999" if n == 999999
  unpadded_str = n.to_s

  # Pad the string with leading zeroes if it is less than
  # 6 digits long.
  # "0" would be padded to "000000"
  # "123" would be padded to "000123"
  # "999999" would not be padded, and remains unchanged as "999999"
  padded_str = unpadded_str.rjust(6, '0')

12

你可以用数学来实现:

(SecureRandom.random_number(9e5) + 1e5).to_i

然后进行验证:

100000.times.map do
  (SecureRandom.random_number(9e5) + 1e5).to_i
end.map { |v| v.to_s.length }.uniq
# => [6]

这将生成100000到999999的范围内的值:

10000000.times.map do
  (SecureRandom.random_number(9e5) + 1e5).to_i
end.minmax
# => [100000, 999999]

如果您需要更简洁的格式,只需将其包装成方法:

def six_digit_rand
  (SecureRandom.random_number(9e5) + 1e5).to_i
end

谢谢,看起来(SecureRandom.random_number(9e5) + 1e5).to_i就是我要找的。 - gogofan
如何使用此功能生成长度为 n 的随机数? - mrudult
1
请使用 9 * 10**(n-1)10**(n-1) - tadman
尝试将9e5作为参数传递给random_number时出现错误,但是10 ** 6可以正常工作。 - MTarantini
1
@MTarantini 你总是可以使用长格式:1_000_000 - tadman
这个回答恰当地回答了提问者的问题,但是如果其他人也想生成一个六位数字代码(例如用于基于短信的MFA),请参考下面Eliot Sykes回答,那个回答更加安全和全面。 - Prime

0

文档请参照Ruby SecureRand,有很多有趣的技巧。

对于这个问题,我会推荐:(SecureRandom.random_number * 1000000).to_i

文档:random_number(n=0)

如果传入0或者没有传入参数,::random_number返回一个浮点数:0.0 <= ::random_number < 1.0。

然后乘以6位小数(* 1000000)并截取小数部分 (.to_i)

如果允许出现字母,我更喜欢使用.hex

SecureRandom.hex(3) #=> "e15b05"

文档:hex(n=nil)

::hex 生成一个随机的十六进制字符串。
参数 n 指定要生成的随机数的字节数。生成的十六进制字符串的长度是 n 的两倍。
如果未指定 n 或为 nil,则假定为 16。将来可能会更大。
结果可能包含 0-9 和 a-f。
其他选项:
SecureRandom.uuid #=> "3f780c86-6897-457e-9d0b-ef3963fbc0a8" SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
对于创建带有对象的条形码或 uid 的 Rails 应用程序,您可以在对象模型文件中执行以下操作:
before_create :generate_barcode

  def generate_barcode
    begin
      return if self.barcode.present?
      self.barcode = SecureRandom.hex.upcase
    end while self.class.exists?(barcode: barcode)
  end

-2

SecureRandom.random_number(n) 会返回一个在0到n之间的随机数。你可以使用rand函数来实现它。

2.3.1 :025 > rand(10**5..10**6-1)
=> 742840

rand(a..b)会返回a和b之间的随机数。在这里,您将始终获得一个介于10^5和10^6-1之间的6位随机数。


3
为什么你建议使用不安全的rand呢?这真的是一步倒退。 - tadman
3
同意,我不会使用rand,我会坚持使用SecureRandom - gogofan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接