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

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


因为很容易与SecureRandom.alphanumeric:红宝石。

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)

解决方案:操作系统的rand仅约3 / 4的时间SecureRandom。可如果你真的会产生很多的字符串,如果你只是创建了一些随机的字符串,从时间,以时间,我总是去实现更安全的(因为它是更容易和更明确的呼唤也)。


我不记得在哪里找到的,但对我来说,这似乎是最好和最不需要过程的:

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)

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


Array.new(n){[*"0".."9"].sample}.join;其中n=8。

广义的:Array.new(n){[*"A".."Z", *"0".."9"].sample}.join等。——来自这个答案


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

希望能有所帮助。


注意:对于攻击者来说,rand是可预测的,因此可能不安全。如果这是为了生成密码,则绝对应该使用SecureRandom。我用这样的东西:

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 facets的方面使用String#random

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


这个解决方案需要外部依赖,但看起来比另一个更好。

  • 安装gem faker
  • Faker::Lorem.characters(10) # =>"ang9cbhoa8"

  • 鉴于:

    1
    chars = [*('a'..'z'),*('0'..'9')].flatten

    单个表达式可以作为参数传递,允许重复字符:

    1
    Array.new(len) { chars.sample }.join

    我最喜欢的是(:A..:Z).to_a.shuffle[0,8].join。注意,无序播放需要Ruby>1.9。


    我只写了一个小gem random_token,为大多数用例生成随机令牌,享受~

    https://github.com/sibevin/random_令牌


    我最近做了这样的工作,从62个字符中生成一个8字节的随机字符串。字符是0-9,a-z,a-z。我有一个它们的数组,循环8次,从数组中选择一个随机值。这是在一个Rails应用程序中。

    str = ''
    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)和答案的字符数在一起,所以有时可以返回random_string仅只数或字符。这提高了至少一半的与random_string)是将字符和数字。如果你需要的只是在案件的随机数和字符的字符串。


    使用"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等。