it-swarm.cn

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

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

value = ""; 8.times{value  << (65 + Rand(25)).chr}

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

value = ""; 8.times{value << ((Rand(2)==1?65:97) + Rand(25)).chr}

但它看起来像垃圾。

有没有人有更好的方法?

710
Jeff
(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
921
Kent Fredric

为什么不使用SecureRandom?

require 'securerandom'
random_string = SecureRandom.hex

# outputs: 5b5cd0da3121fc53b4bc84d0c8af2e81 (i.e. 32 chars of 0..9, a..f)

SecureRandom还有以下方法:

  • bASE64
  • random_bytes
  • rANDOM_NUMBER

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

763
christopherstyles

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

Rand(36**length).to_s(36)

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

241
Christoffer Möller

该解决方案为激活码生成一串易于阅读的字符;我不希望人们混淆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
167
ImNotQuiteJack

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

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,“ - ”和“_”。如果填充为真,则也使用“=”。

125
Travis Reeder
[*('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. Ruby 1.9

45
Shai Coleman

由于使用SecureRandom.alphanumeric,Ruby 2.5非常简单:

len = 8
SecureRandom.alphanumeric(len)
=> "larHSsgL"

生成包含A-Z,a-z和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左右。如果你生成了很多字符串可能很重要,但如果你不时创建一些随机字符串,我总是会使用更安全的实现(因为它也更容易调用和更明确)。

38
Markus

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

def random_string(length=10)
  chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
  password = ''
  length.times { password << chars[Rand(chars.size)] }
  password
end
30
Travis Reeder
require 'securerandom'
SecureRandom.urlsafe_base64(9)
27
LENZCOM

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

require 'securerandom'
randomstring = SecureRandom.hex(n)

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

24
Srikanta Mahapatro

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

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

13
gr8scott06
require 'sha1'
srand
seed = "--#{Rand(10000)}--#{Time.now}--"
Digest::SHA1.hexdigest(seed)[0,8]
11
Coren

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

 random_string = ('0'..'z').to_a.shuffle.first(8).join

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

random_password = ('0'..'z').to_a.shuffle.first(8).join

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

10
Awais

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"
10
Ragmaanir

请注意: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
8
pencil

我喜欢使用的另一种方法

 Rand(2**256).to_s(36)[0..7]

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

 Rand(2**256).to_s(36).ljust(8,'a')[0..7]
6
user163365
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')

来自Devise的东西

6
Thorpe Obazee

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

def random_string(length = 8)
  Rand(32**length).to_s(32)
end
5
pduersteler

你可以使用Ruby Gem facets的Facets中的String#random

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
5
Tilo

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

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
5
Nathan Long

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

4
Josh

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

  1. 安装gem faker
  2. Faker::Lorem.characters(10) # => "ang9cbhoa8"
4
asiniy

鉴于:

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

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

Array.new(len) { chars.sample }.join
4
Tim James

我的2美分:

  def token(length=16)
    chars = [*('A'..'Z'), *('a'..'z'), *(0..9)]
    (0..length).map {chars.sample}.join
  end
3
tybro0103

我只是写了一个小宝石random_token来生成大多数用例的随机令牌,享受〜

https://github.com/sibevin/random_token

3
Sibevin Wang
''.tap {|v| 4.times { v << ('a'..'z').to_a.sample} }
3
eric

我最近正在做这样的事情来生成一个由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是巨大的,但是在db中1200个左右的代码中有大量的重复数据。我注意到它们发生在彼此的小时边界上。换句话说,我可能会在12:12:23和2:12:22看到一个重复的东西......或者类似的东西......不确定时间是否是问题。

此代码位于创建activerecord对象之前。在创建记录之前,此代码将运行并生成“唯一”代码。数据库中的条目总是可靠地生成,但代码(上面一行中的str)经常被复制。

我创建了一个脚本来运行上述行的100000次迭代,延迟很小,所以需要3-4个小时,希望每小时看到某种重复模式,但什么也看不见。我不知道为什么在我的Rails应用程序中发生了这种情况。

3
erik

如果你在UNIX上并且仍然必须使用没有Rails的Ruby 1.8(没有SecureRandom),你也可以使用:

random_string = `openssl Rand -base64 24`

请注意,这会产生新的Shell,这非常慢,只能推荐用于脚本。

2
lzap

另一个适用于Ruby 1.8+并且速度快的技巧是:

>> require "openssl"
>> OpenSSL::Random.random_bytes(20).unpack('H*').join
=> "2f3ff53dd712ba2303a573d9f9a8c1dbc1942d28"

它是随机的十六进制字符串。类似的方式你应该能够生成base64字符串('M *')。

2
lzap

我认为,到目前为止,我最喜欢Radar的答案。我有点像这样调整:

CHARS = ('a'..'z').to_a + ('A'..'Z').to_a
def Rand_string(length=8)
  s=''
  length.times{ s << CHARS[Rand(CHARS.length)] }
  s
end
2
webmat

使用此方法,您可以传入任意长度。默认设置为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
2
Ryan Bigg

我最好的镜头,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)*""
2
peter

试试这个

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方法。

2
Manuel A. Guilamo

这是另一种方法:

  • 它使用安全随机数生成器而不是Rand()
  • 可以在URL和文件名中使用
  • 包含大写,小写字符和数字
  • 可以选择不包含模糊字符I0l01

需要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
2
Evgenii
10.times do 
  alphabet = ('a'..'z').to_a
  string += alpha[Rand(alpha.length)]
end
1
mminski

这是基于其他一些答案,但它增加了一点复杂性:

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
Chris Bloom

对于devise secure_validatable,您可以使用它

(0 ... 8)。map {([65,97] .sample + Rand(26))。chr} .Push(Rand(99))。join

1
shiva kumar

以下是@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中至少有一半是字符,其余的是数字。以防您需要带有数字和字符的随机字符串

0
Lucas Andrade

为了使你的第一个声明:

(0...8).collect { |n| value  << (65 + Rand(25)).chr }.join()
0
Kevin Conner

最简单的方法是使用string_pattern gem https://github.com/MarioRuiz/string_pattern

例如,生成36个随机字母:

 require 'string_pattern'
 puts '36:L'.gen

您也可以使用正则表达式

 require 'string_pattern'
 puts /[a-zA-Z]{36}/.gen
0
Mario Ruiz

如果需要,创建一个空字符串或预修复:

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"
0
Ghazi
a='';8.times{a<<[*'a'..'z'].sample};p a

要么

8.times.collect{[*'a'..'z'].sample}.join
0
Michael Kingski

我们一直在我们的代码上使用它:

class String

  def self.random(length=10)
    ('a'..'z').sort_by {Rand}[0,length].join
  end

end

支持的最大长度为25(我们只使用默认值,因此不是问题)。

有人提到'a'..'z'如果你想完全避免产生令人反感的话,那就不是最理想的了。我们的一个想法是删除元音,但你仍然最终得到了WTFBBQ等。

0
Carlos Villela
`pwgen 8 1`.chomp
0
Nathan L Smith

这是一个灵活的解决方案,允许重复:

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个项目,然后加入它们。

0
Abdo
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
0
Automatico

使用'SafeRandom'宝石 GithubLink

它将为Rails2,Rails 3,Rails 4,Rails 5兼容生成随机值提供最简单的方法。

0
Rubyist