How to Generate a Random String in Ruby

How to generate a random string in 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

How to generate a random string in 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

Generate pseudo random string A-Z, 0-9

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

How would i generate a random and unique string in Ruby?

I use this :)

def generate_token(column, length = 64)
begin
self[column] = SecureRandom.urlsafe_base64 length
end while Model.exists?(column => self[column])
end

Replace Model by your model name

Generate Unique Random String With Letters And Numbers In Lower Case

If you are using ruby 1.9.2 you can use SecureRandom:

irb(main):001:0> require 'securerandom'
=> true
irb(main):002:0> SecureRandom.hex(13)
=> "5bbf194bcf8740ae8c9ce49e97"
irb(main):003:0> SecureRandom.hex(15)
=> "d2413503a9618bacfdb1745eafdb0f"
irb(main):004:0> SecureRandom.hex(32)
=> "432e0a359bbf3669e6da610d57ea5d0cd9e2fceb93e7f7989305d89e31073690"

How to generate a random string in rails

You can have your f.input as such

<%= f.text_field :name, id: :bug_name, value: "#{SecureRandom.hex(64)}" %>

Unique random string with alphanumberic required in Ruby

down   = ('a'..'z').to_a
up = ('A'..'Z').to_a
digits = ('0'..'9').to_a
all = down + up + digits
[down.sample, up.sample, digits.sample].
concat(7.times.map { all.sample }).
shuffle.
join
#=> "TioS8TYw0F"

[Edit: The above reflects a misunderstanding of the question. I'll leave it, however. To have no characters appear more than once:

def rnd_str
down = ('a'..'z').to_a
up = ('A'..'Z').to_a
digits = ('0'..'9').to_a
[extract1(down), extract1(up), extract1(digits)].
concat(((down+up+digits).sample(7))).shuffle.join
end

def extract1(arr)
i = arr.size.times.to_a.sample
c = arr[i]
arr.delete_at(i)
c
end

rnd_str #=> "YTLe0WGoa1"
rnd_str #=> "NrBmAnE9bT"

down.sample.shift (etc.) would have been more compact than extract1, but the inefficiency was just too much to bear.

If you do not want to repeat random strings, simply keep a list of the ones you generate. If you generate another that is in the list, discard it and generate another. It's pretty unlikely you'll have to generate any extra ones, however. If, for example, you generate 100 random strings (satisfying the requirement of at least one lowercase letter, uppercase letter and digit), the chances that there will be one or more duplicate strings is about one in 700,000:

t = 107_518_933_731
n = t+1
t = t.to_f
(1.0 - 100.times.reduce(1.0) { |prod,_| prod * (n -= 1)/t }).round(10)
#=> 1.39e-07

where t = C(62,10) and C(62,10) is defined below.

An alternative

There is a really simple way to do this that turns out to be pretty efficient: just sample without replacement until a sample is found that meets the requirement of at least lowercase letter, one uppercase letter and one digit. We can do that as follows:

DOWN   = ('a'..'z').to_a
UP = ('A'..'Z').to_a
DIGITS = ('0'..'9').to_a
ALL = DOWN + UP + DIGITS

def rnd_str
loop do
arr = ALL.sample(10)
break arr.shuffle.join unless (DOWN&&arr).empty? || (UP&&arr).empty? ||
(DIGITS&&arr).empty?
end
end

rnd_str #=> "3jRkHcP7Ge"
rnd_str #=> "B0s81x4Jto

How many samples must we reject, on average, before finding a "good" one? It turns out (see below if you are really, really interested) that the probability of getting a "bad" string (i.e, selecting 10 characters at random from the 62 elements of all, without replacement, that has no lowercase letters, no uppercase letters or no digits, is only about 0.15. (15%). That means that 85% of the time no bad samples will be rejected before a good one is found.

It turns out that the expected number of bad strings that will be sampled, before a good string is sampled, is:

0.15/0.85 =~ 0.17

The following shows how the above probability was derived, should anyone be interested.

Let n_down be the number of ways a sample of 10 can be drawn that has no lowercase letters:

n_down = C(36,10) = 36!/(10!*(36-10)!)

where (the binomial coefficient) C(36,10) equals the number of combinations of 36 "things" that can be "taken" 10 at a time, and equals:

C(36,10) = 36!/(10!*(36-10)!) #=> 254_186_856

Similarly,

n_up = n_down #=> 254_186_856

and

n_digits = C(52,10) #=> 15_820_024_220

We can add these three numbers together to obtain:

n_down + n_up + n_digits #=> 16_328_397_932

This is almost, but not quite, the number of ways to draw 10 characters, without replacement, that contains no lowercase letters characters, uppercase letters or digits. "Not quite" because there is a bit of double-counting going on. The necessary adjustment is as follows:

n_down + n_up + n_digits - 2*C(26,10) - 3
#=> 16_317_774_459

To obtain the probability of drawing a sample of 10 from a population of 62, without replacement, that has no lowercase letter, no uppercase letter or no digit, we divide this number by the total number of ways 10 characters can be drawn from 62 without replacement:

(16_317_774_459.0/c(62,10)).round(2)
#=> 0.15

Generate random string from key

I am assuming from your question that you want for some reason to associate an input string to a random-looking output, and to have it be the same output if the same key is presented.

The code below will generate the same "random" string for the same input secret key, accepting keys up to 8 * 624 = 4992 bytes long. Technically this is not random, but using Ruby's built in random number generator to hash the input string.

def rand_hash secret_key
int_key = secret_key.unpack("C*").each_with_index.inject(0) do |sum, (byte, index)|
sum + byte * (256 ** index)
end
r = Random.new( int_key )
(0...50).map { ('a'..'z').to_a[ r.rand(26) ] }.join
end

rand_hash "Hi, how are you today?"
# => "mwerzokwwtlqepizuqimbhxmzexmovzrwgvarjlfbkcqpffhoq"

rand_hash "Hi, how are you today?"
# => "mwerzokwwtlqepizuqimbhxmzexmovzrwgvarjlfbkcqpffhoq"

rand_hash "Hi, how are you today!"
# => "zeudwqltlozjdebamemplwllqftmyhdzapatqhdsbnrzfcrmss"

See How do I unpack a number larger than 64 bits in ruby? for how the secret_key is unpacked from a string into a BigNum called int_key.

We then use that key to seed a Ruby Random object (based on Mersenne Twister)

Then use the new Random object to generate the string, same as you do originally.

Note this is not cryptographically secure. If you want security, such as impossibility to reverse the output and find the secret, then you should use a secure hash mechanism (from an appropriate gem such as openssl), and convert that to the character set you require.

customised random string generator in ruby

Try this:

def gen_pass(lengths, number_of_numbers, number_of_special_chars)
chars = ('a'..'z').to_a + ('A'..'Z').to_a + (0..10).to_a
digits = (0..9).to_a
special_chars = "?<>',?[]}{=-)(*&^%$#`~{}".split('')
remaining_letters_count = lengths - number_of_numbers - number_of_special_chars

n = digits.sample(number_of_numbers)
s = special_chars.sample(number_of_special_chars)
c = chars.sample(remaining_letters_count)

str = n << s << c
str.flatten.shuffle.join
end

puts gen_pass(lengths, number_of_numbers, number_of_special_chars)


Related Topics



Leave a reply



Submit