How to generate a random string in Ruby
我目前正在为"a"生成一个8个字符的伪随机大写字符串。Z:
1 | value =""; 8.times{value << (65 + rand(25)).chr} |
但它看起来不干净,而且不能作为参数传递,因为它不是一条语句。要获得混合大小写字符串"a"……Z"加上"A"…"Z",我改为:
1 | value =""; 8.times{value << ((rand(2)==1?65:97) + rand(25)).chr} |
但它看起来像垃圾。
有人有更好的方法吗?
1 | (0...8).map { (65 + rand(26)).chr }.join |
我花了太多时间打高尔夫球。
1 | (0...50).map { ('a'..'z').to_a[rand(26)] }.join |
最后一个更混乱,但更灵活,浪费更少的周期:
1 2 | o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten string = (0...50).map { o[rand(o.length)] }.join |
为什么不使用SecureRandom?
1 2 3 4 | require 'securerandom' random_string = SecureRandom.hex # outputs: 5b5cd0da3121fc53b4bc84d0c8af2e81 (i.e. 32 chars of 0..9, a..f) |
SecureRandom还具有以下方法:
- Base64
- 随机字节
- 随机数
参见:http://ruby-doc.org/stdlib-1.9.2/libdoc/securelrandom/rdoc/securelrandom.html
我使用它生成随机的URL友好字符串,保证最大长度:
1 | rand(36**length).to_s(36) |
它生成小写a-z和0-9的随机字符串。它不是很可定制,但它又短又干净。
这个解决方案为激活代码生成一个易于阅读的字符串;我不希望人们混淆8与B、1与I、0与O、L与1等。
1 2 3 4 5 | # 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安全功能。
1 2 3 4 | require 'securerandom' p SecureRandom.urlsafe_base64(5) #=>"UtM7aa8" p SecureRandom.urlsafe_base64 #=>"UZLdOkzop70Ddx-IJR0ABg" p SecureRandom.urlsafe_base64(nil, true) #=>"i0XQ-7gglIsHGV2_BNPrdQ==" |
结果可能包含a-z、a-z、0-9、"-"和"uu"。如果padding为true,则也使用"="。
1 | [*('A'..'Z')].sample(8).join |
生成随机8个字母的字符串(例如nvayxhgr)
1 | ([*('A'..'Z'),*('0'..'9')]-%w(0 1 I O)).sample(8).join |
生成一个随机的8个字符串(例如3ph4swf2),不包括0/1/i/o.ruby 1.9
因为很容易与
1 2 3 | len = 8 SecureRandom.alphanumeric(len) =>"larHSsgL" |
随机字符串生成含Z、Z、0—9,因此,应该是最适用的案件中使用。他们是随机生成的和安全的,这可能是有益的,太。
编辑:基准的解决方案,它具有相对最upvotes:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 |
1 2 3 | user system total real SecureRandom 0.429442 0.002746 0.432188 ( 0.432705) rand 0.306650 0.000716 0.307366 ( 0.307745) |
解决方案:操作系统的
我不记得在哪里找到的,但对我来说,这似乎是最好和最不需要过程的:
1 2 3 4 5 6 | def random_string(length=10) chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789' password = '' length.times { password << chars[rand(chars.size)] } password end |
1 2 | require 'securerandom' SecureRandom.urlsafe_base64(9) |
如果需要指定长度的字符串,请使用:
1 2 | require 'securerandom' randomstring = SecureRandom.hex(n) |
它将生成包含
广义的:
1 2 3 4 | require 'sha1' srand seed ="--#{rand(10000)}--#{Time.now}--" Digest::SHA1.hexdigest(seed)[0,8] |
红宝石1.9 +:
1 2 3 4 5 6 7 8 9 10 | 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" |
下面是一行简单的代码,用于长度为8的随机字符串
1 | random_string = ('0'..'z').to_a.shuffle.first(8).join |
您也可以将其用于长度为8的随机密码
1 | random_password = ('0'..'z').to_a.shuffle.first(8).join |
我希望它会有帮助,令人惊叹。
下面是一个简单的随机密码代码,使用lenth 8
1 | rand_password=('0'..'z').to_a.shuffle.first(8).join |
希望能有所帮助。
注意:对于攻击者来说,
1 2 3 4 5 6 | 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 |
我喜欢用的另一种方法
1 | rand(2**256).to_s(36)[0..7] |
添加ljust如果您真的对正确的字符串长度有疑虑:
1 | rand(2**256).to_s(36).ljust(8,'a')[0..7] |
1 | SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz') |
设计的东西
我认为这是一个简洁、清晰和易于修改的很好的平衡。
1 2 3 | characters = ('a'..'z').to_a + ('A'..'Z').to_a # Prior to 1.9, use .choice, not .sample (0..8).map{characters.sample}.join |
容易修改的
例如,包括数字:
1 | characters = ('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a |
大写十六进制:
1 | characters = ('A'..'F').to_a + (0..9).to_a |
对于一系列真正令人印象深刻的人物:
1 | characters = (32..126).to_a.pack('U*').chars.to_a |
您可以从ruby gem
https://github.com/rubyworks/facets/blob/126a619fd766bc5588cac18d09c4f1927538e33/lib/core/facets/string/random.rb
基本上是这样的:
1 2 3 4 5 6 7 | 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 |
只是在这里加我的分…
1 2 3 | def random_string(length = 8) rand(32**length).to_s(32) end |
这个解决方案需要外部依赖,但看起来比另一个更好。
鉴于:
1 | chars = [*('a'..'z'),*('0'..'9')].flatten |
单个表达式可以作为参数传递,允许重复字符:
1 | Array.new(len) { chars.sample }.join |
我最喜欢的是
我只写了一个小gem
https://github.com/sibevin/random_令牌
我最近做了这样的工作,从62个字符中生成一个8字节的随机字符串。字符是0-9,a-z,a-z。我有一个它们的数组,循环8次,从数组中选择一个随机值。这是在一个Rails应用程序中。
8.times {|i| str << ARRAY_OF_POSSIBLE_VALUES[rand(SIZE_OF_ARRAY_OF_POSSIBLE_VALUES)] }
奇怪的是我有很多副本。现在随机地,这应该是永远不会发生的。62^8是巨大的,但在数据库中大约1200个代码中,我有很多重复的。我注意到它们发生在彼此的时间界限上。换言之,我可能会在12:12:23和2:12:22看到一个二重唱或类似的事情……不确定时间是否是问题所在。
此代码位于创建ActiveRecord对象之前。在创建记录之前,此代码将运行并生成"唯一"代码。数据库中的条目总是可靠地生成的,但是代码(上面一行中的str)被复制得太频繁了。
我创建了一个脚本,用很小的延迟运行上面这行的100000次迭代,所以需要3-4个小时,希望每小时看到某种重复模式,但什么也没有看到。我不知道为什么在我的Rails应用程序中会发生这种情况。
我的2分钱:
1 2 3 4 | def token(length=16) chars = [*('A'..'Z'), *('a'..'z'), *(0..9)] (0..length).map {chars.sample}.join end |
1 | ''.tap {|v| 4.times { v << ('a'..'z').to_a.sample} } |
试试这个
1 2 3 4 5 6 7 8 9 | 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()方法。我觉得这不太合适,因为我们已经有了数组选择方法。
我认为,到目前为止,我最喜欢雷达的回答。我会这样调整一下:
1 2 3 4 5 6 | CHARS = ('a'..'z').to_a + ('A'..'Z').to_a def rand_string(length=8) s='' length.times{ s << CHARS[rand(CHARS.length)] } s end |
用这种方法,你可以通过一个小长度。默认设置为6。
1 2 3 4 5 6 7 8 | def generate_random_string(length=6) string ="" chars = ("A".."Z").to_a length.times do string << chars[rand(chars.length-1)] end string end |
Ruby1.8+的另一个技巧是:
1 2 3 | >> require"openssl" >> OpenSSL::Random.random_bytes(20).unpack('H*').join =>"2f3ff53dd712ba2303a573d9f9a8c1dbc1942d28" |
它得到的是你随机的十六进制字符串。类似地,您应该能够生成base64字符串("m*")。
我的最佳镜头,3个范围的随机字符串的2个解决方案
1 2 3 | (('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)*"" |
如果您在Unix上,并且您仍然必须使用Ruby1.8(非SecureRandom)而不使用Rails,那么您也可以使用它:
1 | random_string = `openssl rand -base64 24` |
注意,这会生成新的shell,速度非常慢,只能推荐用于脚本。
另一种方法是:
- 它使用安全随机数生成器而不是rand()。
- 可用于URL和文件名
- 包含大写、小写字符和数字
- 具有不包含不明确字符的选项i0l01
需要EDOCX1[0]
1 2 3 4 5 6 7 8 9 10 11 | 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 |
为了设计安全的,你可以使用这个
(0…8).map([65,97].sample+rand(26)).chr.push(rand(99)).join
这是基于其他一些答案,但它增加了一点复杂性:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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个字符,并且至少包含一个数字和一个特殊字符。
1 2 3 4 | 10.times do alphabet = ('a'..'z').to_a string += alpha[rand(alpha.length)] end |
以下是一个灵活的解决方案,允许重复数据消除:
1 2 3 4 5 6 7 | 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 |
例子:
1 | "ATCG".random(8) =>"CGTGAAGA" |
您还可以允许某个字符更频繁地出现:
1 | "AAAAATCG".random(10) =>"CTGAAAAAGC" |
说明:上面的方法获取给定字符串的字符并生成足够大的数组。然后对其进行无序处理,获取前n个项,然后将它们联接起来。
1 2 3 4 5 | 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 |
1 | `pwgen 8 1`.chomp |
如果需要,请创建空字符串或预修复:
1 | myStr ="OID-" |
使用此代码用随机数填充字符串:
1 | begin; n = ((rand * 43) + 47).ceil; myStr << n.chr if !(58..64).include?(n); end while(myStr.length < 12) |
笔记:
1 | (rand * 43) + 47).ceil |
它将从48-91(0,1,2..y,z)生成随机数。
1 | !(58..64).include?(n) |
它用于跳过特殊字符(因为我不想包括它们)
1 | while(myStr.length < 12) |
它将生成总共12个字符长的字符串,包括前缀。
样品输出:
1 | "OID-XZ2J32XM" |
该方法是使用easiest字符串模式的创业板_ https:/ / / / _ github.com marioruiz字符串模式
例如:36生成随机字母
1 2 | require 'string_pattern' puts '36:L'.gen |
也可以使用正则表达式
1 2 | require 'string_pattern' puts /[a-zA-Z]{36}/.gen |
把你的第一句话写成一句话:
1 | (0...8).collect { |n| value << (65 + rand(25)).chr }.join() |
1 | a='';8.times{a<<[*'a'..'z'].sample};p a |
或
1 | 8.times.collect{[*'a'..'z'].sample}.join |
我们在代码中使用了这个:
1 2 3 4 5 6 7 | class String def self.random(length=10) ('a'..'z').sort_by {rand}[0,length].join end end |
支持的最大长度是25(我们只在默认情况下使用它,所以没有问题)。
有人提到,如果你想完全避免产生冒犯性的词语,"a"…"z"是次优的。我们的一个想法是去掉元音,但是你最终还是得到了wtfbq等等。
在这里,R是(答案:提高"特拉维斯
1 2 3 4 5 6 7 8 | 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 |
"特拉维斯(R)和答案的字符数在一起,所以有时可以返回
使用"githublink saferandom宝石
它将提供easiest生成随机值的方式是rails2 Rails,Rails的3,4,5上的兼容。
这几乎是丑陋的,但也许是正确的方向?
1 | (1..8).map{|i| ('a'..'z').to_a[rand(26)]}.join |
在Ruby1.9中,可以使用数组的choice方法,该方法从数组中返回随机元素。
我不知道Ruby,所以我不能给出确切的语法,但是我会用可接受字符列表设置一个常量字符串,然后使用substring操作符从中选择一个随机字符。
这里的优点是,如果字符串应该是用户可输入的,那么您可以排除容易混淆的字符,如l和1、i、0和o、5和s等。