如何在Ruby中生成随机字符串

Jef*_*eff 729 ruby random passwords

我正在为"A"生成一个8个字符的伪随机大写字符串."Z":

value = ""; 8.times{value  << (65 + rand(25)).chr}
Run Code Online (Sandbox Code Playgroud)

但它看起来并不干净,并且它不能作为参数传递,因为它不是单个语句.要获得一个混合大小写的字符串"a".."z"加上"A".."Z",我将其更改为:

value = ""; 8.times{value << ((rand(2)==1?65:97) + rand(25)).chr}
Run Code Online (Sandbox Code Playgroud)

但它看起来像垃圾.

有没有人有更好的方法?

Ken*_*ric 945

(0...8).map { (65 + rand(26)).chr }.join
Run Code Online (Sandbox Code Playgroud)

我花太多时间打高尔夫球.

(0...50).map { ('a'..'z').to_a[rand(26)] }.join
Run Code Online (Sandbox Code Playgroud)

而最后一个更令人困惑,但更灵活,浪费更少的周期:

o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten
string = (0...50).map { o[rand(o.length)] }.join
Run Code Online (Sandbox Code Playgroud)

  • 34个字符和超快速:`('a'..'z').to_a.shuffle [0,8] .join`.注意你需要Ruby> = 1.9到`shuffle`. (200认同)
  • `[*('a'..'z'),*('0'..'9')].shuffle [0,8] .join`生成一个包含字母和数字的随机字符串. (32认同)
  • `rand`具有确定性和可预测性.不要用它来生成密码!使用其中一个`SecureRandom`解决方案. (30认同)
  • @faraz你的方法在功能上是不一样的,它不随机替换. (28认同)
  • 除非您有自己的驱动程序,否则最好利用现有的库.在其他答案中,请参阅`SecureRandom`作为一个示例. (18认同)
  • 使用`shuffle`的解决方案不会那么棒,因为它们会产生一次出现字符的字符串(所以字符串如"gbalgqut"将是不可能的 - 双"g") (4认同)
  • 始终使用SecureRandom等现有解决方案,转而采用自行开发的"随机"解决方案.说真的,他们是有原因的. (3认同)
  • 最后一个例子应该是`(0 ... 50).map {[('a'..'z'),('A'..'Z')].flat_map(&:to_a).sample}.加入`你肯定*没有*花费很多时间打高尔夫xD (2认同)
  • 我刚刚创建了一个模块“ RandomString”,总结了所有答案中提到的三种主要技术:https://gist.github.com/jopotts/8706578 (2认同)
  • @TanelSuurhans作为这个答案的OP,我同意所有关于"使用经过验证的测试工具"的观点.就在这个答案的时候,这些工具还不是核心,作者似乎把打高尔夫作为一个目标.了解您的语言如何工作与使用该语言编写的工具一样重要. (2认同)

小智 784

为什么不使用SecureRandom?

require 'securerandom'
random_string = SecureRandom.hex

# outputs: 5b5cd0da3121fc53b4bc84d0c8af2e81 (i.e. 32 chars of 0..9, a..f)
Run Code Online (Sandbox Code Playgroud)

SecureRandom还有以下方法:

  • BASE64
  • random_bytes
  • RANDOM_NUMBER

请参阅:http://ruby-doc.org/stdlib-1.9.2/libdoc/securerandom/rdoc/SecureRandom.html

  • 顺便说一句,它是1.9和最近的1.8版本中的stdlib的一部分,所以可以只需要'secure'ndom'`来获得这个整洁的`SecureRandom`帮助器:) (67认同)
  • BTW SecureRandom已从3.2版的ActiveSupport中删除.来自更改日志:"从标准库中删除了ActiveSupport :: SecureRandom以支持SecureRandom". (21认同)
  • `SecureRandom.random_number(36**12).to_s(36).rjust(12,"0")`将生成一个0-9a-z(36个字符)的字符串,总长度为12个字符.将12更改为您想要的任何长度.不幸的是,没有办法只使用`Integer#to_s`获得AZ. (15认同)
  • base64会,但不是像他的例子中的十六进制 (11认同)

小智 245

我使用它来生成具有保证最大长度的随机URL友好字符串:

rand(36**length).to_s(36)
Run Code Online (Sandbox Code Playgroud)

它生成小写az和0-9的随机字符串.它不是很可定制,但它简洁干净.

  • 这是一个很好的解决方案(并且速度很快),但它偶尔会产生一个低于*`length`长度的字符串*,大约一次在~40 (12认同)
  • 这里的版本总是产生所需长度的标记:`(36**(长度-1)+兰特(36**长度 - 36**(长度-1))).to_s(36)` (11认同)
  • @Brian E这将保证你想要的数字:`(36**(长度-1)+兰特(36**长度)).to_s(36)`.36**(长度-1)转换为基数36是10**(长度-1),这是具有您想要的数字长度的最小值. (7认同)
  • 最短版本的+1(不调用外部二进制文件^^).如果随机字符串不是公开的,我有时甚至只使用`rand.to_s`; 丑陋,但有效. (4认同)
  • 这在Rails 4和Ruby 2.1.1中为我吐出错误:`NameError:undefined局部变量或main:Object的方法`length' (3认同)

小智 171

该解决方案为激活码生成一串易于阅读的字符; 我不希望人们混淆8与B,1与I,0与O,L与1混淆等.

# Generates a random string from a set of easily readable characters
def generate_activation_code(size = 6)
  charset = %w{ 2 3 4 6 7 9 A C D E F G H J K M N P Q R T V W X Y Z}
  (0...size).map{ charset.to_a[rand(charset.size)] }.join
end
Run Code Online (Sandbox Code Playgroud)

  • @gtd - 是的.U和V是ambigvov. (9认同)
  • 为了安全起见,您还需要使用`SecureRandom.random_number(charset.size)`而不是`rand(charset.size)` (8认同)
  • 'U'是暧昧还是错字? (3认同)
  • 我只是想通过添加小写和/或一些特殊字符(shift+num)来改进这一点,并得到以下列表: `%w{ ACDEFGHJKLMNPQRTWXYZ 2 3 4 6 7 9 !@# $ % ^ &amp; * +}` 和 `%w{ ADEFGHJLNQRTY adefhnry 2 3 4 7 ! @ # $ % ^ &amp; * }` (第一个列表不包括小写字母,但它更长)结果有点有趣。 (2认同)

Tra*_*der 127

其他人提到类似的东西,但这使用了URL安全功能.

require 'securerandom'
p SecureRandom.urlsafe_base64(5) #=> "UtM7aa8"
p SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
p SecureRandom.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="
Run Code Online (Sandbox Code Playgroud)

结果可能包含AZ,az,0-9," - "和"_".如果填充为真,则也使用"=".


Mar*_*kus 58

由于ruby 2.5非常容易搭配SecureRandom.alphanumeric:

len = 8
SecureRandom.alphanumeric(len)
=> "larHSsgL"
Run Code Online (Sandbox Code Playgroud)

生成包含AZ,az和0-9的随机字符串,因此应适用于大多数用例.并且它们是随机生成的,这也可能是一个好处.


编辑:将其与具有最多投票的解决方案进行比较的基准:

require 'benchmark'
require 'securerandom'

len = 10
n = 100_000

Benchmark.bm(12) do |x|
  x.report('SecureRandom') { n.times { SecureRandom.alphanumeric(len) } }
  x.report('rand') do
    o = [('a'..'z'), ('A'..'Z'), (0..9)].map(&:to_a).flatten
    n.times { (0...len).map { o[rand(o.length)] }.join }
  end
end
Run Code Online (Sandbox Code Playgroud)
                   user     system      total        real
SecureRandom   0.429442   0.002746   0.432188 (  0.432705)
rand           0.306650   0.000716   0.307366 (  0.307745)
Run Code Online (Sandbox Code Playgroud)

所以rand解决方案只需要大约3/4的时间SecureRandom.如果你生成了很多字符串可能很重要,但如果你不时创建一些随机字符串,我总是会使用更安全的实现(因为它也更容易调用和更明确).


Sha*_*man 47

[*('A'..'Z')].sample(8).join
Run Code Online (Sandbox Code Playgroud)

生成一个随机的8个字母的字符串(例如NVAYXHGR)

([*('A'..'Z'),*('0'..'9')]-%w(0 1 I O)).sample(8).join
Run Code Online (Sandbox Code Playgroud)

生成随机8字符串(例如3PH4SWF2),不包括0/1/I/O. Ruby 1.9

  • 唯一的问题是结果中的每个字符都是唯一的.限制可能的值. (4认同)

Tra*_*der 30

我不记得我发现了什么,但对我来说似乎是最好的,也是最不重要的过程:

def random_string(length=10)
  chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
  password = ''
  length.times { password << chars[rand(chars.size)] }
  password
end
Run Code Online (Sandbox Code Playgroud)

  • 也许你在这里找到了它?http://travisonrails.com/2007/06/07/generate-random-text-with-ruby (7认同)
  • 故意丢失了"0"和"1"以及"O"和"我",因为这些字符含糊不清.如果使用此类代码生成用户需要复制的一组字符,则最好排除可能难以区分的字符. (4认同)

小智 27

require 'securerandom'
SecureRandom.urlsafe_base64(9)
Run Code Online (Sandbox Code Playgroud)

  • 顺便说一句,urlsafe_base64返回一个字符串,大约是指示长度的4/3.要获得一个字符串n chars long,请尝试`n = 9; SecureRandom.urlsafe_base64(N)[0..N-1]` (4认同)

小智 25

如果需要指定长度的字符串,请使用:

require 'securerandom'
randomstring = SecureRandom.hex(n)
Run Code Online (Sandbox Code Playgroud)

它将生成一个2n包含0-9和的随机字符串长度a-f


gr8*_*t06 13

Array.new(n){[*"0".."9"].sample}.join,在你的情况下n = 8.

广义:n=8等等 - 从这个答案


小智 11

require 'sha1'
srand
seed = "--#{rand(10000)}--#{Time.now}--"
Digest::SHA1.hexdigest(seed)[0,8]
Run Code Online (Sandbox Code Playgroud)

  • 请记住,十六进制摘要仅返回0-9和af字符. (3认同)

Rag*_*nir 10

Ruby 1.9+:

ALPHABET = ('a'..'z').to_a
#=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]

10.times.map { ALPHABET.sample }.join
#=> "stkbssowre"

# or

10.times.inject('') { |s| s + ALPHABET.sample }
#=> "fdgvacnxhc"
Run Code Online (Sandbox Code Playgroud)


Awa*_*ais 10

这是一行长度为8的随机字符串简单代码

 random_string = ('0'..'z').to_a.shuffle.first(8).join
Run Code Online (Sandbox Code Playgroud)

您也可以将它用于长度为8的随机密码

random_password = ('0'..'z').to_a.shuffle.first(8).join
Run Code Online (Sandbox Code Playgroud)

我希望它会有所帮助和惊人.

  • 您不应该使用它来生成自己的密码,因为此方法永远不会重复一个字符.因此,你只使用8个字符的可能字符空间的'P(36,8)/ 36 ^ 8 = 0.4`(~2x更容易暴力)或'P(36,25)/ 36 ^ 25 = 0.00001 `25个字符的可能字符空间(~100,000x更容易暴力). (2认同)

Tha*_* kp 8

这是一个简单的随机密码代码,带有lenth 8

rand_password=('0'..'z').to_a.shuffle.first(8).join
Run Code Online (Sandbox Code Playgroud)

希望它会有所帮助.


pen*_*cil 8

请注意:rand攻击者可以预测,因此可能不安全.如果这是用于生成密码,您肯定应该使用SecureRandom.我使用这样的东西:

length = 10
characters = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a

password = SecureRandom.random_bytes(length).each_char.map do |char|
  characters[(char.ord % characters.length)]
end.join
Run Code Online (Sandbox Code Playgroud)


use*_*365 7

我喜欢使用的另一种方法

 rand(2**256).to_s(36)[0..7]
Run Code Online (Sandbox Code Playgroud)

如果您对正确的字符串长度非常偏执,请添加:

 rand(2**256).to_s(36).ljust(8,'a')[0..7]
Run Code Online (Sandbox Code Playgroud)


Tee*_*eej 6

SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
Run Code Online (Sandbox Code Playgroud)

来自Devise的东西


Nat*_*ong 5

我认为这是简洁,清晰和易于修改的良好平衡.

characters = ('a'..'z').to_a + ('A'..'Z').to_a
# Prior to 1.9, use .choice, not .sample
(0..8).map{characters.sample}.join
Run Code Online (Sandbox Code Playgroud)

轻松修改

例如,包括数字:

characters = ('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a
Run Code Online (Sandbox Code Playgroud)

大写十六进制:

characters = ('A'..'F').to_a + (0..9).to_a
Run Code Online (Sandbox Code Playgroud)

对于真正令人印象深刻的人物阵列:

characters = (32..126).to_a.pack('U*').chars.to_a
Run Code Online (Sandbox Code Playgroud)


pdu*_*ler 5

在这里加我的分钱......

def random_string(length = 8)
  rand(32**length).to_s(32)
end
Run Code Online (Sandbox Code Playgroud)

  • 注意:这并不总是正确地返回一个字符串+长度+长 - 它可能更短.这取决于`rand`返回的数字 (3认同)

Til*_*ilo 5

你可以使用String#randomRuby Gem的Facets facets:

https://github.com/rubyworks/facets/blob/126a619fd766bc45588cac18d09c4f1927538e33/lib/core/facets/string/random.rb

它基本上是这样的:

class String
  def self.random(len=32, character_set = ["A".."Z", "a".."z", "0".."9"])
    characters = character_set.map { |i| i.to_a }.flatten
    characters_len = characters.length
    (0...len).map{ characters[rand(characters_len)] }.join
  end
end
Run Code Online (Sandbox Code Playgroud)