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?
546 Answers
(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
13Why 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
I use this for generating random URL friendly strings with a length between 1 and string_length characters:
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.
12This 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 7Since 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.
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.
0[*('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
4I 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 5require 'securerandom' SecureRandom.urlsafe_base64(9) 2If 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".
0require 'sha1' srand seed = "--#{rand(10000)}--#{Time.now}--" Digest::SHA1.hexdigest(seed)[0,8] 3Ruby 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" 4Here 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 1Be 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 1Another 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] 1SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz') Something from Devise
3Here is one simple code for random password with length 8:
rand_password=('0'..'z').to_a.shuffle.first(8).join 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 1Just adding my cents here...
def random_string(length = 8) rand(32**length).to_s(32) end 1You 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 This solution needs external dependency, but seems prettier than another.
- Install gem faker
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 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.
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 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 3My 2 cents:
def token(length=16) chars = [*('A'..'Z'), *('a'..'z'), *(0..9)] (0..length).map {chars.sample}.join end My favorite is (:A..:Z).to_a.shuffle[0,8].join. Note that shuffle requires Ruby > 1.9.
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*').
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" 1