[英]How to generate a random string in Ruby
我目前正在为 "A" .. "Z" 生成一个 8 个字符的伪随机大写字符串:
value = ""; 8.times{value << (65 + rand(25)).chr}
但它看起来并不干净,并且不能作为参数传递,因为它不是单个语句。 为了得到一个大小写混合的字符串 "a" .. "z" 加上 "A" .. "Z",我把它改成了:
value = ""; 8.times{value << ((rand(2)==1?65:97) + rand(25)).chr}
但它看起来像垃圾。
有人有更好的方法吗?
(0...8).map { (65 + rand(26)).chr }.join
我花了太多时间打高尔夫球。
(0...50).map { ('a'..'z').to_a[rand(26)] }.join
最后一个更令人困惑,但更灵活,浪费更少的周期:
o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten
string = (0...50).map { o[rand(o.length)] }.join
如果要生成一些随机文本,请使用以下命令:
50.times.map { (0...(rand(10))).map { ('a'..'z').to_a[rand(26)] }.join }.join(" ")
此代码生成 50 个单词长度小于 10 个字符的随机单词字符串,然后用空格连接
为什么不使用 SecureRandom?
require 'securerandom'
random_string = SecureRandom.hex
# outputs: 5b5cd0da3121fc53b4bc84d0c8af2e81 (i.e. 32 chars of 0..9, a..f)
SecureRandom 还具有以下方法:
见: http : //ruby-doc.org/stdlib-1.9.2/libdoc/securerandom/rdoc/SecureRandom.html
我使用它来生成具有保证最大长度的随机 URL 友好字符串:
string_length = 8
rand(36**string_length).to_s(36)
它生成小写 az 和 0-9 的随机字符串。 它不是很可定制,但它简短而干净。
该解决方案为激活码生成一串易于阅读的字符; 我不希望人们将 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
其他人提到了类似的东西,但这使用了 URL 安全功能。
require 'securerandom'
p SecureRandom.urlsafe_base64(5) #=> "UtM7aa8"
p SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
p SecureRandom.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="
结果可能包含AZ、az、0-9、“-”和“_”。 如果填充为真,也使用“=”。
从 Ruby 2.5 开始,使用SecureRandom.alphanumeric
真的很容易:
len = 8
SecureRandom.alphanumeric(len)
=> "larHSsgL"
它生成包含 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
user system total real
SecureRandom 0.429442 0.002746 0.432188 ( 0.432705)
rand 0.306650 0.000716 0.307366 ( 0.307745)
所以rand
解决方案只需要SecureRandom
大约 3/4 的时间。 如果您生成大量字符串,这可能很重要,但如果您只是不时创建一些随机字符串,我总是会采用更安全的实现,因为它也更容易调用且更明确。
[*('A'..'Z')].sample(8).join
生成一个随机的 8 个字母的字符串(例如 NVAYXHGR)
([*('A'..'Z'),*('0'..'9')]-%w(0 1 I O)).sample(8).join
生成一个随机的 8 个字符串(例如 3PH4SWF2),不包括 0/1/I/O。 红宝石 1.9
我不记得我在哪里找到的,但对我来说它似乎是最好的和最少的过程密集型:
def random_string(length=10)
chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
password = ''
length.times { password << chars[rand(chars.size)] }
password
end
require 'securerandom'
SecureRandom.urlsafe_base64(9)
如果需要指定长度的字符串,请使用:
require 'securerandom'
randomstring = SecureRandom.hex(n)
它将生成一个长度2n
的随机字符串,其中包含0-9
和af
Array.new(n){[*"0".."9"].sample}.join
,其中n=8
在你的情况下。
广义: Array.new(n){[*"A".."Z", *"0".."9"].sample}.join
等。
来自:“ 生成伪随机字符串AZ,0-9 ”。
这是长度为 8 的随机字符串的一行简单代码:
random_string = ('0'..'z').to_a.shuffle.first(8).join
您还可以将其用于长度为 8 的随机密码:
random_password = ('0'..'z').to_a.shuffle.first(8).join
红宝石 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"
require 'sha1'
srand
seed = "--#{rand(10000)}--#{Time.now}--"
Digest::SHA1.hexdigest(seed)[0,8]
这是长度为 8 的随机密码的一个简单代码:
rand_password=('0'..'z').to_a.shuffle.first(8).join
请注意: 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
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
来自设计的东西
我喜欢使用的另一种方法:
rand(2**256).to_s(36)[0..7]
如果您真的对正确的字符串长度感到偏执,请添加ljust
:
rand(2**256).to_s(36).ljust(8,'a')[0..7]
我认为这是简洁、清晰和易于修改之间的很好的平衡。
characters = ('a'..'z').to_a + ('A'..'Z').to_a
# Prior to 1.9, use .choice, not .sample
(0..8).map{characters.sample}.join
例如,包括数字:
characters = ('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a
大写十六进制:
characters = ('A'..'F').to_a + (0..9).to_a
对于真正令人印象深刻的字符数组:
characters = (32..126).to_a.pack('U*').chars.to_a
只是在这里添加我的美分...
def random_string(length = 8)
rand(32**length).to_s(32)
end
您可以使用来自 Ruby Gem facets
的 Facets 的String#random
。
它基本上是这样做的:
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
我最喜欢的是(:A..:Z).to_a.shuffle[0,8].join
。 请注意,shuffle 需要 Ruby > 1.9。
这个解决方案需要外部依赖,但看起来比另一个更漂亮。
Faker::Lorem.characters(10) # => "ang9cbhoa8"
我最近在做这样的事情,从 62 个字符生成一个 8 字节的随机字符串。 字符为 0-9,az,AZ。 我有一个数组,循环 8 次并从数组中选择一个随机值。 这是在 Rails 应用程序中。
str = ''
8.times {|i| str << ARRAY_OF_POSSIBLE_VALUES[rand(SIZE_OF_ARRAY_OF_POSSIBLE_VALUES)] }
奇怪的是我得到了很多重复。 现在随机这应该几乎永远不会发生。 62^8 是巨大的,但是在 db 中的 1200 个左右的代码中,我有很多重复的代码。 我注意到它们发生在彼此的小时界限上。 换句话说,我可能会在 12:12:23 和 2:12:22 或类似的地方看到一个重复...不确定时间是否是问题。
此代码在创建 ActiveRecord 对象之前。 在创建记录之前,此代码将运行并生成“唯一”代码。 数据库中的条目总是可靠地生成,但是代码(上一行中的str
)被重复得太频繁了。
我创建了一个脚本来运行上面这条线的 100000 次迭代,延迟很小,所以需要 3-4 个小时,希望每小时看到某种重复模式,但什么也没看到。 我不知道为什么这会发生在我的 Rails 应用程序中。
鉴于:
chars = [*('a'..'z'),*('0'..'9')].flatten
单个表达式,可以作为参数传递,允许重复字符:
Array.new(len) { chars.sample }.join
我的 2 美分:
def token(length=16)
chars = [*('A'..'Z'), *('a'..'z'), *(0..9)]
(0..length).map {chars.sample}.join
end
我只是写了一个小 gem random_token
来为大多数用例生成随机令牌,享受吧~
''.tap {|v| 4.times { v << ('a'..'z').to_a.sample} }
我认为到目前为止,我最喜欢雷达的回答。 我会稍微调整一下:
CHARS = ('a'..'z').to_a + ('A'..'Z').to_a
def rand_string(length=8)
s=''
length.times{ s << CHARS[rand(CHARS.length)] }
s
end
由 3 个范围组成的随机字符串的 2 个解决方案:
(('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a).sample(8).join
([*(48..57),*(65..90),*(97..122)]).sample(8).collect(&:chr)*""
如果您需要每个范围中的至少一个字符,例如创建一个包含一个大写、一个小写字母和一个数字的随机密码,您可以执行以下操作:
( ('a'..'z').to_a.sample(8) + ('A'..'Z').to_a.sample(8) + (0..9).to_a.sample(8) ).shuffle.join
#=> "Kc5zOGtM0H796QgPp8u2Sxo1"
如果您在 UNIX 上并且仍然必须使用 Ruby 1.8(无 SecureRandom)而不使用 Rails,您也可以使用以下命令:
random_string = `openssl rand -base64 24`
请注意,这会生成新的 shell,这非常慢,只能推荐用于脚本。
另一个适用于 Ruby 1.8+ 并且速度很快的技巧是:
>> require "openssl"
>> OpenSSL::Random.random_bytes(20).unpack('H*').join
=> "2f3ff53dd712ba2303a573d9f9a8c1dbc1942d28"
它让你随机十六进制字符串。 类似的方式你应该能够生成 base64 字符串('M*')。
试试这个
def rand_name(len=9)
ary = [('0'..'9').to_a, ('a'..'z').to_a, ('A'..'Z').to_a]
name = ''
len.times do
name << ary.choice.choice
end
name
end
我喜欢线程的答案,确实非常有帮助!,但如果我可以说,它们都不能满足我的要求,也许是 rand() 方法。 这对我来说似乎不正确,因为我们已经有了 Array#choice 方法。
这是另一种方法:
需求require "securerandom"
def secure_random_string(length = 32, non_ambiguous = false)
characters = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
%w{I O l 0 1}.each{ |ambiguous_character|
characters.delete ambiguous_character
} if non_ambiguous
(0...length).map{
characters[ActiveSupport::SecureRandom.random_number(characters.size)]
}.join
end
我们一直在我们的代码中使用它:
class String
def self.random(length=10)
('a'..'z').sort_by {rand}[0,length].join
end
end
支持的最大长度为 25(我们只使用默认值,所以没有问题)。
有人提到如果你想完全避免产生冒犯性的词,'a'..'z' 是次优的。 我们的想法之一是删除元音,但最终还是得到 WTFBBQ 等。
使用此方法,您可以传入一个abitrary长度。 默认设置为6。
def generate_random_string(length=6)
string = ""
chars = ("A".."Z").to_a
length.times do
string << chars[rand(chars.length-1)]
end
string
end
这是基于其他一些答案,但它增加了一点复杂性:
def random_password
specials = ((32..47).to_a + (58..64).to_a + (91..96).to_a + (123..126).to_a).pack('U*').chars.to_a
numbers = (0..9).to_a
alpha = ('a'..'z').to_a + ('A'..'Z').to_a
%w{i I l L 1 O o 0}.each{ |ambiguous_character|
alpha.delete ambiguous_character
}
characters = (alpha + specials + numbers)
password = Random.new.rand(8..18).times.map{characters.sample}
password << specials.sample unless password.join =~ Regexp.new(Regexp.escape(specials.join))
password << numbers.sample unless password.join =~ Regexp.new(Regexp.escape(numbers.join))
password.shuffle.join
end
从本质上讲,它确保密码长度为 8 - 20 个字符,并且至少包含一个数字和一个特殊字符。
10.times do
alphabet = ('a'..'z').to_a
string += alpha[rand(alpha.length)]
end
对于设计secure_validatable,您可以使用它
(0...8).map { ([65, 97].sample + rand(26)).chr }.push(rand(99)).join
这是@Travis R 答案的改进:
def random_string(length=5)
chars = 'abdefghjkmnpqrstuvwxyzABDEFGHJKLMNPQRSTUVWXYZ'
numbers = '0123456789'
random_s = ''
(length/2).times { random_s << numbers[rand(numbers.size)] }
(length - random_s.length).times { random_s << chars[rand(chars.size)] }
random_s.split('').shuffle.join
end
在@Travis R 回答字符和数字在一起,因此有时random_string
只能返回数字或仅返回字符。 通过这种改进,至少有一半的random_string
将是字符,其余的是数字。 以防万一你需要一个带有数字和字符的随机字符串
如果需要,创建一个空字符串或前缀:
myStr = "OID-"
使用此代码用随机数填充字符串:
begin; n = ((rand * 43) + 47).ceil; myStr << n.chr if !(58..64).include?(n); end while(myStr.length < 12)
笔记:
(rand * 43) + 47).ceil
它将生成从 48-91 (0,1,2..Y,Z) 的随机数
!(58..64).include?(n)
它用于跳过特殊字符(因为我对包含它们不感兴趣)
while(myStr.length < 12)
它将生成总共 12 个字符长的字符串,包括前缀。
示例输出:
"OID-XZ2J32XM"
这是一个灵活且允许重复的解决方案:
class String
# generate a random string of length n using current string as the source of characters
def random(n)
return "" if n <= 0
(chars * (n / length + 1)).shuffle[0..n-1].join
end
end
例子:
"ATCG".random(8) => "CGTGAAGA"
您还可以允许某个字符更频繁地出现:
"AAAAATCG".random(10) => "CTGAAAAAGC"
说明:上面的方法取给定字符串的字符并生成一个足够大的数组。 然后打乱它,取前 n 个项目,然后加入它们。
Array.new(8).inject(""){|r|r<<('0'..'z').to_a.shuffle[0]} # 57
(1..8).inject(""){|r|r<<('0'..'z').to_a.shuffle[0]} # 51
e="";8.times{e<<('0'..'z').to_a.shuffle[0]};e # 45
(1..8).map{('0'..'z').to_a.shuffle[0]}.join # 43
(1..8).map{rand(49..122).chr}.join # 34
`pwgen 8 1`.chomp
a='';8.times{a<<[*'a'..'z'].sample};p a
或者
8.times.collect{[*'a'..'z'].sample}.join
使用“SafeRandom”Gem GithubLink
它将提供为 Rails2、Rails 3、Rails 4、Rails 5 兼容生成随机值的最简单方法。
把你的第一个语句变成一个语句:
(0...8).collect { |n| value << (65 + rand(25)).chr }.join()
在 ruby 1.9 中,可以使用数组的选择方法,该方法从数组中返回随机元素
这几乎同样丑陋,但也许是朝着正确方向迈出的一步?
(1..8).map{|i| ('a'..'z').to_a[rand(26)]}.join
我不知道 ruby,所以我不能给你确切的语法,但我会用可接受的字符列表设置一个常量字符串,然后使用子字符串运算符从中挑选一个随机字符。
这里的优点是,如果字符串应该是用户可输入的,那么您可以排除容易混淆的字符,如 l 和 1 和 i、0 和 O、5 和 S 等。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.