[ruby] How to generate a random string in Ruby

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?

This question is related to ruby random passwords

The answer is


(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

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


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.


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

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.


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.


[*('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


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

require 'securerandom'
SecureRandom.urlsafe_base64(9)

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


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: "Generate pseudo random string A-Z, 0-9".


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

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

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"

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

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

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

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]

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

Something from Devise


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

Just adding my cents here...

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

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

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


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

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

Given:

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

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

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

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

My 2 cents:

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

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

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"

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

https://github.com/sibevin/random_token


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.


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

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

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*').


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

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

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.


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.


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


For devise secure_validatable you can use this

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


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.


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

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.


Use 'SafeRandom' Gem GithubLink

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


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

or

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

To make your first into one statement:

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

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.


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

To make your first into one statement:

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

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"

`pwgen 8 1`.chomp

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


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

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

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.


Questions with ruby tag:

Uninitialized Constant MessagesController Embed ruby within URL : Middleman Blog Titlecase all entries into a form_for text field Ruby - ignore "exit" in code Empty brackets '[]' appearing when using .where find_spec_for_exe': can't find gem bundler (>= 0.a) (Gem::GemNotFoundException) How to update Ruby Version 2.0.0 to the latest version in Mac OSX Yosemite? How to fix "Your Ruby version is 2.3.0, but your Gemfile specified 2.2.5" while server starting Is the server running on host "localhost" (::1) and accepting TCP/IP connections on port 5432? How to update Ruby with Homebrew? Ruby: How to convert a string to boolean Can't install gems on OS X "El Capitan" How to resolve "gpg: command not found" error during RVM installation? How to install Ruby 2.1.4 on Ubuntu 14.04 The authorization mechanism you have provided is not supported. Please use AWS4-HMAC-SHA256 Cannot install Aptana Studio 3.6 on Windows AWS S3: The bucket you are attempting to access must be addressed using the specified endpoint How to avoid "cannot load such file -- utils/popen" from homebrew on OSX RVM is not a function, selecting rubies with 'rvm use ...' will not work How to solve error "Missing `secret_key_base` for 'production' environment" (Rails 4.1) Check if not nil and not empty in Rails shortcut? ActionController::UnknownFormat Failed to build gem native extension (installing Compass) Rails formatting date converting epoch time with milliseconds to datetime TypeError: no implicit conversion of Symbol into Integer RSpec: how to test if a method was called? Execute a command line binary with Node.js Error while installing json gem 'mkmf.rb can't find header files for ruby' How to downgrade or install an older version of Cocoapods How to select option in drop down using Capybara PG::ConnectionBad - could not connect to server: Connection refused Append key/value pair to hash with << in Ruby How to delete specific characters from a string in Ruby? Create Directory if it doesn't exist with Ruby SSL Error When installing rubygems, Unable to pull data from 'https://rubygems.org/ Rails 4 LIKE query - ActiveRecord adds quotes How to find where gem files are installed Installing RubyGems in Windows Rails 4: assets not loading in production Which Ruby version am I really running? Installing Bootstrap 3 on Rails App Rails 4: List of available datatypes Why do I get a "permission denied" error while installing a gem? How to install a specific version of a ruby gem? Rails 4: before_filter vs. before_action Rails 4 Authenticity Token Testing for empty or nil-value string Ruby class instance variable vs. class variable Determining type of an object in ruby

Questions with random tag:

How can I get a random number in Kotlin? scikit-learn random state in splitting dataset Random number between 0 and 1 in python In python, what is the difference between random.uniform() and random.random()? Generate random colors (RGB) Random state (Pseudo-random number) in Scikit learn How does one generate a random number in Apple's Swift language? How to generate a random string of a fixed length in Go? Generate 'n' unique random numbers within a range What does random.sample() method in python do? random.seed(): What does it do? Generate random array of floats between a range How to Generate a random number of fixed length using JavaScript? How can I generate a random number in a certain range? Creating a random string with A-Z and 0-9 in Java Generating a Random Number between 1 and 10 Java Display SQL query results in php Generate random numbers using C++11 random library Postgres FOR LOOP best practice to generate random token for forgot password Random word generator- Python random number generator between 0 - 1000 in c# generate a random number between 1 and 10 in c Python: Random numbers into a list How to use function srand() with time.h? How to hash a string into 8 digits? Java generating non-repeating random numbers Random row selection in Pandas dataframe Select 50 items from list at random to write to file Simple way to create matrix of random numbers android.content.res.Resources$NotFoundException: String resource ID Fatal Exception in Main Why does this code using random strings print "hello world"? Generating random, unique values C# Laravel - Eloquent or Fluent random row rand() returns the same number each time the program is run Reasons for using the set.seed function How does C#'s random number generator work? How to generate a random number in C++? How to generate random float number in C Random element from string array Java random numbers using a seed How to properly seed random number generator How do I generate random numbers in Dart? How to randomize Excel rows Get random boolean in Java Random alpha-numeric string in JavaScript? rand() between 0 and 1 How to get records randomly from the oracle database? How do I create a list of random numbers without duplicates? Generate random password string with requirements in javascript

Questions with passwords tag:

Your password does not satisfy the current policy requirements Laravel Password & Password_Confirmation Validation Default password of mysql in ubuntu server 16.04 mcrypt is deprecated, what is the alternative? What is the default root pasword for MySQL 5.7 MySQL user DB does not have password columns - Installing MySQL on OSX Changing an AIX password via script? Hide password with "•••••••" in a textField How to create a laravel hashed password Enter export password to generate a P12 certificate ASP.NET Identity's default Password Hasher - How does it work and is it secure? What's the default password of mariadb on fedora? How to log in to phpMyAdmin with WAMP, what is the username and password? How to code a very simple login system with java How to get back Lost phpMyAdmin Password, XAMPP encrypt and decrypt md5 Error # 1045 - Cannot Log in to MySQL server -> phpmyadmin How to decrypt the password generated by wordpress Execute ssh with password authentication via windows command prompt Javascript regular expression password validation having special characters How to send password using sftp batch file Programmatically change input type of the EditText from PASSWORD to NORMAL & vice versa Salt and hash a password in Python Getting command-line password input in Python Why is char[] preferred over String for passwords? C# password TextBox in a ASP.net website Masking password input from the console : Java Setting the MySQL root user password on OS X How to reset Django admin password? Generating a random password in php Can anyone confirm that phpMyAdmin AllowNoPassword works with MySQL databases? Android EditText for password with android:hint Regex to validate password strength How to provide password to a command that prompts for one in bash? How do you use bcrypt for hashing passwords in PHP? How to hash a password Password encryption at client side How to change password using TortoiseSVN? How to give credentials in a batch script that copies files to a network location? How to switch between hide and view password Password masking console application Hide/encrypt password in bash file to stop accidentally seeing it How to pass password automatically for rsync SSH command? Where does Internet Explorer store saved passwords? How to save password when using Subversion from the console How can I hash a password in Java? Cannot import the keyfile 'blah.pfx' - error 'The keyfile may be password protected' How to find out the username and password for mysql database Simple way to encode a string according to a password? How do I login and authenticate to Postgresql after a fresh install?