Creating somewhat readable words in Ruby

495 views Asked by At

I'm trying to create somewhat readable words in ruby containing upper case, lowercase, numbers, and a special character, something like:

FlAshmnger!2
Derfing$23

To create a random string in ruby you can do something like this:

lower = ('a'...'z').to_a
upper = ('A'...'Z').to_a
numbers = (0...9).to_a
specs = %w(! ? * ^ $)
size = 8

charset = [lower, upper, numbers, specs].flatten
(0...size).map { charset[rand(charset.size)] }.join
#<= ?!VVQUjH
#<= ^tsm^Led

Is there a way I could make sure that the random string is somewhat readable? Containing a constant, vowel, etc.. With a special character and at least one number without the use of an external gem?

2

There are 2 answers

0
Eric Duminil On BEST ANSWER

Creating your password from scratch

Using this gist as a basis :

class PasswordGenerator
  # Original version : https://gist.github.com/lpar/1031933
  # Simple generation of readable random passwords using Ruby
  # by lpar

  # These are the koremutake syllables, plus the most common 2 and 3 letter 
  # syllables taken from the most common 5,000 words in English, minus a few
  # syllables removed so that combinations cannot generate common rude
  # words in English.
  SYLLABLES = %w(ba be bi bo bu by da de di do du dy fe fi fo fu fy ga ge gi
        go gu gy ha he hi ho hu hy ja je ji jo ju jy ka ke ko ku ky la le li lo 
        lu ly ma me mi mo mu my na ne ni no nu ny pa pe pi po pu py ra re ri ro 
        ru ry sa se si so su sy ta te ti to tu ty va ve vi vo vu vy bra bre bri 
        bro bru bry dra dre dri dro dru dry fra fre fri fro fru fry gra gre gri 
        gro gru gry pra pre pri pro pru pry sta ste sti sto stu sty tra tre er 
        ed in ex al en an ad or at ca ap el ci an et it ob of af au cy im op co 
        up ing con ter com per ble der cal man est for mer col ful get low son 
        tle day pen pre ten tor ver ber can ple fer gen den mag sub sur men min 
        out tal but cit cle cov dif ern eve hap ket nal sup ted tem tin tro tro)

  def initialize
    srand
  end

  def generate(length)
    result = ''
    while result.length < length
      syl = SYLLABLES[rand(SYLLABLES.length)]
      result += syl
    end
    result = result[0,length]
    # Stick in a symbol
    spos = rand(length)
    result[spos,1] = %w(! ? * ^ $).sample
    # Stick in a digit, possibly over the symbol
    dpos = rand(length)
    result[dpos,1] = rand(9).to_s
    # Make a letter capitalized
    cpos = rand(length)
    result[cpos,1] = result[cpos,1].swapcase
    return result
  end
end

pwgen = PasswordGenerator.new

10.times do
  puts pwgen.generate(10)
end

Output example :

Mageve$7ur
Pehu5ima^r
a!hub8osta
b5gobrY^er
miN!e3inyf
manb1ufr^p
d^m0ndeRca
Ter5esur$b
m8r$omYket
gyso5it^le

Using pwgen

You could also just install pwgen and use :

%x(pwgen).chomp
#=> "aipeebie"

and for more complex passwords :

%x(pwgen --symbols --numerals --capitalize #{length}).chomp
#=> "Ma[Foh1EeX"

Correct horse battery staple

Following the recommendations of this XKCD comic, you could just pick 4 common words out of a dictionary (e.g. /usr/share/dict/american-english).

0
Sagar Pandya On

Correcting your ranges slightly by using .. instead of ..., this includes the final element in each range:

lower = ('a'..'z').to_a
upper = ('A'..'Z').to_a
numbers = (0..9).to_a
specs = %w(! ? * ^ $)

charset = [lower, upper, numbers, specs]

Then say if you want say two from each character set, you can use Enumerable#inject like this:

charset.inject([]) { |memo,obj| memo + obj.sample(2) }.shuffle.join
#=> "Lf5^$O2u"

Something more custom:

def rand_string (l,u,n,s)
  (('a'..'z').to_a.sample(l) +
   ('A'..'Z').to_a.sample(u) +
   (0..9).to_a.sample(n)     +
   %w(! ? * ^ $).sample(s)).shuffle.join
end

Then a weighted random string with 3 lower letters, 3 uppercase letters, 3 numbers and 1 special character would be:

rand_string(3,3,3,1)
#=> "ic!I04OEr7"