How to generate a random string in Ruby

RubyRandomPasswords

Ruby Problem Overview


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?

Ruby Solutions


Solution 1 - Ruby

(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

If you want to generate some random text then use the following:

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

this code generates 50 random word string with words length less than 10 characters and then join with space

Solution 2 - Ruby

Why not use SecureRandom?

require 'securerandom'
random_string = SecureRandom.hex

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

SecureRandom also has methods for:

  • base64
  • random_bytes
  • random_number

see: http://ruby-doc.org/stdlib-1.9.2/libdoc/securerandom/rdoc/SecureRandom.html

Solution 3 - Ruby

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

string_length = 8
rand(36**string_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.

Solution 4 - Ruby

This solution generates a string of easily readable characters for activation codes; I didn't want people confusing 8 with B, 1 with I, 0 with O, L with 1, etc.

# 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

Solution 5 - Ruby

Others have mentioned something similar, but this uses the URL safe function.

require 'securerandom'
p SecureRandom.urlsafe_base64(5) #=> "UtM7aa8"
p SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
p SecureRandom.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="

The result may contain A-Z, a-z, 0-9, “-” and “_”. “=” is also used if padding is true.

Solution 6 - Ruby

Since Ruby 2.5, it's really easy with SecureRandom.alphanumeric:

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

It 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.


This is 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. That might matter if you generate 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.

Solution 7 - Ruby

[*('A'..'Z')].sample(8).join

Generate a random 8 letter string (e.g. NVAYXHGR)

([*('A'..'Z'),*('0'..'9')]-%w(0 1 I O)).sample(8).join

Generate a random 8 character string (e.g. 3PH4SWF2), excludes 0/1/I/O. Ruby 1.9

Solution 8 - Ruby

I can't remember where I found this, but it seems like the best and the least process intensive to me:

def random_string(length=10)
  chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
  password = ''
  length.times { password << chars[rand(chars.size)] }
  password
end

Solution 9 - Ruby

require 'securerandom'
SecureRandom.urlsafe_base64(9)

Solution 10 - Ruby

If you want a string of specified length, use:

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

It will generate a random string of length 2n containing 0-9 and a-f

Solution 11 - Ruby

Array.new(n){[*"0".."9"].sample}.join, where n=8 in your case.

Generalized: Array.new(n){[*"A".."Z", *"0".."9"].sample}.join, etc.

From: "https://stackoverflow.com/questions/26076011/rails-generate-pseudo-random-string-a-z-0-9/26076063#26076063";.

Solution 12 - Ruby

Here is one line simple code for random string with length 8:

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

You can also use it for random password having length 8:

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

Solution 13 - Ruby

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

Solution 14 - Ruby

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"

Solution 15 - Ruby

Here is one simple code for random password with length 8:

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

Solution 16 - Ruby

Be aware: rand is predictable for an attacker and therefore probably insecure. You should definitely use SecureRandom if this is for generating passwords. I use something like this:

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

Solution 17 - Ruby

Another method I like to use:

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

Add ljust if you are really paranoid about the correct string length:

 rand(2**256).to_s(36).ljust(8,'a')[0..7]

Solution 18 - Ruby

SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')

Something from Devise

Solution 19 - Ruby

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

Solution 20 - Ruby

Just adding my cents here...

def random_string(length = 8)
  rand(32**length).to_s(32)
end

Solution 21 - Ruby

You can use String#random from the Facets of Ruby Gem facets.

It basically does this:

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

Solution 22 - Ruby

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

  1. Install gem faker
  2. Faker::Lorem.characters(10) # => "ang9cbhoa8"

Solution 23 - Ruby

I was doing something like this recently to generate an 8 byte random string from 62 characters. The characters were 0-9,a-z,A-Z. I had an array of them as was looping 8 times and picking a random value out of the array. This was inside a Rails app.

str = ''
8.times {|i| str << ARRAY_OF_POSSIBLE_VALUES[rand(SIZE_OF_ARRAY_OF_POSSIBLE_VALUES)] }

The weird thing is that I got good number of duplicates. Now randomly this should pretty much never happen. 62^8 is huge, but out of 1200 or so codes in the db i had a good number of duplicates. I noticed them happening on hour boundaries of each other. In other words I might see a duple at 12:12:23 and 2:12:22 or something like that...not sure if time is the issue or not.

This code was in the before create of an ActiveRecord object. Before the record was created this code would run and generate the 'unique' code. Entries in the DB were always produced reliably, but the code (str in the above line) was being duplicated much too often.

I created a script to run through 100000 iterations of this above line with small delay so it would take 3-4 hours hoping to see some kind of repeat pattern on an hourly basis, but saw nothing. I have no idea why this was happening in my Rails app.

Solution 24 - Ruby

Given:

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

Single expression, can be passed as an argument, allows duplicate characters:

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

Solution 25 - Ruby

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

Solution 26 - Ruby

I like Radar's answer best, so far, I think. I'd tweak a bit like this:

CHARS = ('a'..'z').to_a + ('A'..'Z').to_a
def rand_string(length=8)
  s=''
  length.times{ s << CHARS[rand(CHARS.length)] }
  s
end

Solution 27 - Ruby

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

Solution 28 - Ruby

2 solutions for a random string consisting of 3 ranges:

(('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)*""
One Character from each Range.

And if you need at least one character from each range, such as creating a random password that has one uppercase, one lowercase letter and one digit, you can do something like this:

( ('a'..'z').to_a.sample(8) + ('A'..'Z').to_a.sample(8) + (0..9).to_a.sample(8) ).shuffle.join 
#=> "Kc5zOGtM0H796QgPp8u2Sxo1"

Solution 29 - Ruby

My 2 cents:

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

Solution 30 - Ruby

I just write a small gem random_token to generate random tokens for most use case, enjoy ~

https://github.com/sibevin/random_token

Solution 31 - Ruby

We've been using this on our code:

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

The maximum length supported is 25 (we're only using it with the default anyway, so hasn't been a problem).

Someone mentioned that 'a'..'z' is suboptimal if you want to completely avoid generating offensive words. One of the ideas we had was removing vowels, but you still end up with WTFBBQ etc.

Solution 32 - Ruby

With this method you can pass in an abitrary length. It's set as a default as 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

Solution 33 - Ruby

try this out

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

I love the answers of the thread, have been very helpful, indeed!, but if I may say, none of them satisfies my ayes, maybe is the rand() method. it's just doesn't seems right to me, since we've got the Array#choice method for that matter.

Solution 34 - Ruby

Here is another method:

  • It uses the secure random number generator instead of rand()
  • Can be used in URLs and file names
  • Contains uppercase, lowercase characters and numbers
  • Has an option not to include ambiguous characters I0l01

Needs 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

Solution 35 - Ruby

If you are on a UNIX and you still must use Ruby 1.8 (no SecureRandom) without Rails, you can also use this:

random_string = `openssl rand -base64 24`

Note this spawns new shell, this is very slow and it can only be recommended for scripts.

Solution 36 - Ruby

Another trick that works with Ruby 1.8+ and is fast is:

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

It get's you random hex string. Similar way you should be able to generate base64 string ('M*').

Solution 37 - Ruby

This is based on a few other answers, but it adds a bit more complexity:

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

Essentially it ensures a password that is 8 - 20 characters in length, and which contains at least one number and one special character.

Solution 38 - Ruby

10.times do 
  alphabet = ('a'..'z').to_a
  string += alpha[rand(alpha.length)]
end

Solution 39 - Ruby

For devise secure_validatable you can use this

(0...8).map { ([65, 97].sample + rand(26)).chr }.push(rand(99)).join

Solution 40 - Ruby

Here is a improve of @Travis R answer:

 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

At @Travis R answer chars and numbers were together, so sometimes random_string could return only numbers or only characters. With this improve at least half of random_string will be characters and the rest are numbers. Just in case if you need a random string with numbers and characters

Solution 41 - Ruby

To make your first into one statement:

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

Solution 42 - Ruby

`pwgen 8 1`.chomp

Solution 43 - Ruby

Create an empty string or a pre-fix if require:

myStr = "OID-"

Use this code to populate the string with random numbers:

begin; n = ((rand * 43) + 47).ceil; myStr << n.chr if !(58..64).include?(n); end while(myStr.length < 12)

Notes:

(rand * 43) + 47).ceil

It will generate random numbers from 48-91 (0,1,2..Y,Z)

!(58..64).include?(n)

It is used to skip special characters (as I am not interested to include them)

while(myStr.length < 12)

It will generate total 12 characters long string including prefix.

Sample Output:

"OID-XZ2J32XM"

Solution 44 - Ruby

Here's a solution that is flexible and allows dups:

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

Example:

"ATCG".random(8) => "CGTGAAGA"

You can also allow a certain character to appear more frequently:

"AAAAATCG".random(10) => "CTGAAAAAGC"

Explanation: The method above takes the chars of a given string and generates a big enough array. It then shuffles it, takes the first n items, then joins them.

Solution 45 - Ruby

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

Solution 46 - Ruby

a='';8.times{a<<[*'a'..'z'].sample};p a

or

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

Solution 47 - Ruby

Use 'SafeRandom' Gem GithubLink

It will provide the easiest way to generate random values for Rails2, Rails 3, Rails 4, Rails 5 compatible.

Solution 48 - Ruby

The following worked well for me

def generate_random_password(min_length, max_length)
    length = SecureRandom.random_number(max_length - min_length) + min_length
    character_sets = [ 
      ('a'..'z').to_a,
      ('A'..'Z').to_a,
      ('0'..'9').to_a,
      "~!@^&*()_-+=[]|:;<,>.?".split('')
    ]   
    retval = []
    #   
    # Add one character from each set
    #   
    character_sets.each do |character_set|
      character = character_set[SecureRandom.random_number(character_set.count)]
      retval.push character
    end 
    #   
    # Fill the rest of the password with a random character from a random set
    #   
    i = character_sets.count - 1 
    while i < length
      character_set = character_sets[SecureRandom.random_number(character_sets.count)]
      character = character_set[SecureRandom.random_number(character_set.count)]
      retval.push character
      i += 1
    end
    retval.shuffle.join
  end

Solution 49 - Ruby

This is almost as ugly but perhaps as step in right direction?

 (1..8).map{|i| ('a'..'z').to_a[rand(26)]}.join

Solution 50 - Ruby

In ruby 1.9 one can use Array's choice method which returns random element from array

Solution 51 - Ruby

I don't know ruby, so I can't give you the exact syntax, but I would set a constant string with the list of acceptable characters, then use the substring operator to pick a random character out of it.

The advantage here is that if the string is supposed to be user-enterable, then you can exclude easily confused characters like l and 1 and i, 0 and O, 5 and S, etc.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJeffView Question on Stackoverflow
Solution 1 - RubyKent FredricView Answer on Stackoverflow
Solution 2 - RubychristopherstylesView Answer on Stackoverflow
Solution 3 - RubyChristoffer MöllerView Answer on Stackoverflow
Solution 4 - RubyImNotQuiteJackView Answer on Stackoverflow
Solution 5 - RubyTravis ReederView Answer on Stackoverflow
Solution 6 - RubyMarkusView Answer on Stackoverflow
Solution 7 - RubyShai ColemanView Answer on Stackoverflow
Solution 8 - RubyTravis ReederView Answer on Stackoverflow
Solution 9 - RubyLENZCOMView Answer on Stackoverflow
Solution 10 - RubySrikanta MahapatroView Answer on Stackoverflow
Solution 11 - Rubygr8scott06View Answer on Stackoverflow
Solution 12 - RubyAwaisView Answer on Stackoverflow
Solution 13 - RubyCorenView Answer on Stackoverflow
Solution 14 - RubyRagmaanirView Answer on Stackoverflow
Solution 15 - RubyThaha kpView Answer on Stackoverflow
Solution 16 - RubypencilView Answer on Stackoverflow
Solution 17 - Rubyuser163365View Answer on Stackoverflow
Solution 18 - RubyTeejView Answer on Stackoverflow
Solution 19 - RubyNathan LongView Answer on Stackoverflow
Solution 20 - RubypduView Answer on Stackoverflow
Solution 21 - RubyTiloView Answer on Stackoverflow
Solution 22 - RubyasiniyView Answer on Stackoverflow
Solution 23 - RubyerikView Answer on Stackoverflow
Solution 24 - RubyTim JamesView Answer on Stackoverflow
Solution 25 - RubyJoshView Answer on Stackoverflow
Solution 26 - RubywebmatView Answer on Stackoverflow
Solution 27 - RubyericView Answer on Stackoverflow
Solution 28 - RubypeterView Answer on Stackoverflow
Solution 29 - Rubytybro0103View Answer on Stackoverflow
Solution 30 - RubySibevin WangView Answer on Stackoverflow
Solution 31 - RubyCarlos VillelaView Answer on Stackoverflow
Solution 32 - RubyRyan BiggView Answer on Stackoverflow
Solution 33 - RubyManuel A. GuilamoView Answer on Stackoverflow
Solution 34 - RubyEvgeniiView Answer on Stackoverflow
Solution 35 - RubylzapView Answer on Stackoverflow
Solution 36 - RubylzapView Answer on Stackoverflow
Solution 37 - RubyChris BloomView Answer on Stackoverflow
Solution 38 - RubyDDDView Answer on Stackoverflow
Solution 39 - Rubyshiva kumarView Answer on Stackoverflow
Solution 40 - RubyLucas AndradeView Answer on Stackoverflow
Solution 41 - RubyeaseoutView Answer on Stackoverflow
Solution 42 - RubyNathan L SmithView Answer on Stackoverflow
Solution 43 - RubyGhaziView Answer on Stackoverflow
Solution 44 - RubyAbdoView Answer on Stackoverflow
Solution 45 - RubyAutomaticoView Answer on Stackoverflow
Solution 46 - RubyMinskiView Answer on Stackoverflow
Solution 47 - RubyRubyistView Answer on Stackoverflow
Solution 48 - RubyTareq SaifView Answer on Stackoverflow
Solution 49 - RubyPurfideasView Answer on Stackoverflow
Solution 50 - RubymaykeyeView Answer on Stackoverflow
Solution 51 - RubynsayerView Answer on Stackoverflow