views:

10598

answers:

18

I'm currently using the following to generate an 8 character pseudo random upper case string [A-Z]

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

but it looks junky, and since it isn't a single statement it can't be passed as an argument. To get a mixed case string [a-zA-Z] I further hack into it with

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

Just looks like trash. Anyone have a better method?

+1  A: 

To make your first into one statement:

(0...8).collect { |n| value  << (65 + rand(25)).chr }.join()
Kevin Conner
+33  A: 
(0...8).map{65.+(rand(25)).chr}.join

I spend too much time golfing.

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

For lots of good WTFBBQ factor.

And one more that's even more confusing, but more flexible and wastes less cycles:

o =  [('a'..'z'),('A'..'Z')].map{|i| i.to_a}.flatten;  
string  =  (0..50).map{ o[rand(o.length)]  }.join;
Kent Fredric
good point. but, i had a bug, you need "..." not ".."
Kevin Conner
I love the simplicity and understandability and customizability of your solution - Thank You so much!
stringo0
A: 

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.

nsayer
A: 

That's basically the same thing I did for random strings in PHP. The only possible improvement I'd make is to drop that into a function, possibly with an argument for the length of the string if needed, so you can pass the function's return value as an argument.

Jarett
A: 

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

 (1..8).map{|i| ('a'..'z').to_a[rand(26)]}.join
Purfideas
lol. i swear i did't see that before i extended mine. weird.
Kent Fredric
:) I actually love the fastest gun in a perverse way
Purfideas
+3  A: 
require 'sha1'
srand
seed = "--#{rand(10000)}--#{Time.now}--"
Digest::SHA1.hexdigest(seed)[0,8]
Interesting, but quite a bit more computationally expensive
Jeff
Also no capacity for limited scope of characters.
Kent Fredric
Keep in mind that a hex digest returns only 0-9 and a-f characters.
webmat
A: 

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.

Carlos Villela
Your approach can't return repeating characters (e.g, uuunMoBldj)... Is this what's wanted?
webmat
Yes, I suppose that technically isn't really a random string anymore, good find webmat.
Jeff
+1  A: 

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
Ryan Bigg
A: 

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
webmat
+13  A: 

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, 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 L M N P Q R T V W X Y Z}
  (0...size).map{ charset.to_a[rand(charset.size)] }.join
end
Thanks, this is exactly what I wanted to do.
Patrick McCafferty
+1 for avoiding ambiguity in the codes
dertoni
+6  A: 

Can't remember where I found this, but seemed the best to me and least process intense:

    def random_string(length=10)
        chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'
        password = ''
        length.times { password << chars[rand(chars.size)] }
        password
    end
Travis R
A: 

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

maykeye
Thanks for the heads up - however, http://svn.ruby-lang.org/repos/ruby/tags/v1_9_1_0/NEWS seems to indicate that Array#sample is to be used in 1.9.1, not Array#choose / choice
Andrew Grimm
+18  A: 

Why not use SecureRandom, provided by ActiveSupport?

require 'active_support/secure_random'
random_string = ActiveSupport::SecureRandom.hex(16)

# outputs: 5b5cd0da3121fc53b4bc84d0c8af2e81

SecureRandom also has methods for:

  • base64
  • hex
  • random_bytes
  • random_number

see: http://api.rubyonrails.org/classes/ActiveSupport/SecureRandom.html

divisionoftigers
This generates strings that aren't safe for passing as get variables for websites - for example, you can get string=+fGH1 (+ is read as a space), and string=fyhi/ (the slash is used for navigation)
stringo0
+1  A: 

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]
ChaosR
+3  A: 
`pwgen 8 1`.chomp
Nathan L Smith
A: 

Ruby 1.9:

ALPHABET = ('a'..'z').to_a
10.times.map{ ALPHABET.sample }.join
10.times.inject(''){|s| s << ALPHABET.sample }
Ragmaanir
A: 

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.

erik
A: 

I use this for generating random url friendly strings.

rand(32**length).to_s(32)

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

Christoffer Möller