How to generate a random string in Ruby

2019-01-01 09:45发布

I'm currently generating an 8-character pseudo-random uppercase string for "A" .. "Z":

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

but it doesn't look clean, and it can't be passed as an argument since it isn't a single statement. To get a mixed-case string "a" .. "z" plus "A" .. "Z", I changed it to:

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

but it looks like trash.

Does anyone have a better method?

30条回答
笑指拈花
2楼-- · 2019-01-01 10:15

This solution needs external dependency, but seems prettier than another.

  1. Install gem faker
  2. Faker::Lorem.characters(10) # => "ang9cbhoa8"
查看更多
余生请多指教
3楼-- · 2019-01-01 10:17

I think this is a nice balance of conciseness, clarity and ease of modification.

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

Easily modified

For example, including digits:

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

Uppercase hexadecimal:

characters = ('A'..'F').to_a + (0..9).to_a

For a truly impressive array of characters:

characters = (32..126).to_a.pack('U*').chars.to_a
查看更多
像晚风撩人
4楼-- · 2019-01-01 10:17

My favorite is (:A..:Z).to_a.shuffle[0,8].join. Note that shuffle requires Ruby > 1.9.

查看更多
姐姐魅力值爆表
5楼-- · 2019-01-01 10:19

I use this for generating random URL friendly strings with a guaranteed maximum length:

rand(36**length).to_s(36)

It generates random strings of lowercase a-z and 0-9. It's not very customizable but it's short and clean.

查看更多
素衣白纱
6楼-- · 2019-01-01 10:20
(0...8).map { (65 + rand(26)).chr }.join

I spend too much time golfing.

(0...50).map { ('a'..'z').to_a[rand(26)] }.join

And a last one that's even more confusing, but more flexible and wastes fewer cycles:

o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten
string = (0...50).map { o[rand(o.length)] }.join
查看更多
步步皆殇っ
7楼-- · 2019-01-01 10:22

Since ruby 2.5 really easy with SecureRandom.alphanumeric:

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

Generates random strings containing A-Z, a-z and 0-9 and therefore should be applicable in most use cases. And they are generated randomly secure, which might be a benefit, too.


Edit: A benchmark to compare it with the solution having the most upvotes:

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)

So the rand solution only takes about 3/4 of the time of SecureRandom. Might matter if you generate really a lot of strings, but if you just create some random string from time to time I'd always go with the more secure implementation (since it is also easier to call and more explicit).

查看更多
登录 后发表回答