Comment générer une chaîne aléatoire dans Ruby

je suis en train de générer une chaîne d'majuscules pseudo-aléatoires de 8 caractères pour" A".. "Z":

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

mais il ne semble pas propre, et il ne peut pas être passé comme un argument car il n'est pas une seule déclaration. Pour obtenir un casse mixte chaîne "un" .. "z" de plus, "Un" .. "Z" , Je l'ai changé en:

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

mais on dirait une poubelle.

quelqu'un aurait-il une meilleure méthode?

687
demandé sur Jeff 2008-09-18 02:24:44

30 réponses

(0...8).map { (65 + rand(26)).chr }.join

je passe trop de temps au golf.

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

et une dernière qui est encore plus déroutante, mais plus flexible et gaspille moins de cycles:

o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten
string = (0...50).map { o[rand(o.length)] }.join
885
répondu Kent Fredric 2017-03-09 10:56:00

pourquoi ne pas utiliser SecureRandom?

require 'securerandom'
random_string = SecureRandom.hex

# outputs: 5b5cd0da3121fc53b4bc84d0c8af2e81 (i.e. 32 chars of 0..9, a..f)

SecureRandom a également des méthodes pour:

  • base64
  • random_bytes
  • random_number

voir: http://ruby-doc.org/stdlib-1.9.2/libdoc/securerandom/rdoc/SecureRandom.html

744
répondu christopherstyles 2015-06-04 20:07:47

Je l'utilise pour générer des chaînes conviviales D'URL aléatoires avec une longueur maximale garantie:

rand(36**length).to_s(36)

il génère des chaînes aléatoires de minuscules a-z et 0-9. Ce n'est pas très personnalisable mais c'est court et propre.

230
répondu Christoffer Möller 2017-12-04 08:37:57

cette solution génère une chaîne de caractères facilement lisibles pour les codes d'activation; Je ne voulais pas que les gens confondent 8 avec B, 1 avec I, 0 avec O, L avec 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
163
répondu 2 revs, 2 users 86%ImNotQuiteJack 2011-08-25 00:32:31

D'autres ont mentionné quelque chose de similaire, mais cela utilise la fonction de sécurité URL.

require 'securerandom'
p SecureRandom.urlsafe_base64(5) #=> "UtM7aa8"
p SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
p SecureRandom.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="

le résultat peut contenir A-Z, a-z, 0-9, " - "et"_". "=" est également utilisé si le rembourrage est vrai.

120
répondu Travis R 2014-05-16 19:40:12
[*('A'..'Z')].sample(8).join

générer une chaîne aléatoire de 8 lettres (par exemple NVAYXHGR)

([*('A'..'Z'),*('0'..'9')]-%w(0 1 I O)).sample(8).join

génère une chaîne aléatoire de 8 caractères( par exemple 3PH4SWF2), exclut 0/1/I / O. Ruby 1.9

44
répondu Tom Carr 2012-01-22 11:58:53

Je ne me souviens pas où j'ai trouvé ceci, mais il me semble que c'est le meilleur et le processus le moins intensif pour moi:

def random_string(length=10)
  chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
  password = ''
  length.times { password << chars[rand(chars.size)] }
  password
end
30
répondu Travis R 2013-08-24 22:41:44
require 'securerandom'
SecureRandom.urlsafe_base64(9)
27
répondu LENZCOM 2012-07-13 00:34:57

depuis ruby 2.5 vraiment facile avec SecureRandom.alphanumeric :

len = 8
SecureRandom.alphanumeric(len)
=> "larHSsgL"

génère des chaînes aléatoires contenant A-Z, A-z et 0-9 et devrait donc être applicable dans la plupart des cas d'utilisation. Et ils sont générés au hasard sécurisé, ce qui pourrait être un avantage, aussi.


Edit: Un indice de référence à comparer avec la solution ayant le plus 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 la solution rand ne prend qu'environ 3/4 du temps de SecureRandom . Cela peut avoir de l'importance si vous générez vraiment beaucoup de chaînes, mais si vous créez juste quelques chaînes aléatoires de temps en temps, j'irais toujours avec l'implémentation la plus sûre (puisque c'est aussi plus facile à appeler et plus explicite).

25
répondu Markus 2018-01-30 12:39:47

si vous voulez une chaîne de longueur spécifiée, utilisez:

require 'securerandom'
randomstring = SecureRandom.hex(n)

il générera une chaîne aléatoire de longueur 2n contenant 0-9 et a-f

24
répondu Srikanta Mahapatro 2015-05-15 09:28:29

Array.new(n){[*"0".."9"].sample}.join , où n=8 dans votre cas.

généralisé: Array.new(n){[*"A".."Z", *"0".."9"].sample}.join , etc. - de ce réponse

13
répondu gr8scott06 2017-05-23 11:54:59
require 'sha1'
srand
seed = "--#{rand(10000)}--#{Time.now}--"
Digest::SHA1.hexdigest(seed)[0,8]
11
répondu Coren 2008-09-17 22:40:34

Voici une ligne de code simple pour la chaîne aléatoire de la longueur 8

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

vous pouvez également l'utiliser pour le mot de passe aléatoire ayant la longueur 8

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

j'espère que cela vous aidera et incroyable.

10
répondu Awais 2014-11-19 06:12:15

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"
10
répondu Ragmaanir 2016-05-13 15:04:26

voici un code simple pour mot de passe aléatoire avec lenth 8

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

j'Espère que ça aidera.

8
répondu Thaha kp 2012-10-15 06:51:24

soit conscient: rand est prévisible pour un attaquant et donc probablement peu sûr. Vous devriez certainement utiliser SecureRandom si c'est pour générer des mots de passe. J'utilise quelque chose comme ceci:

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
8
répondu pencil 2013-03-30 14:30:32
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')

quelque Chose à partir de Concevoir

6
répondu Thorpe Obazee 2012-04-19 00:25:43

une autre méthode que j'aime utiliser

 rand(2**256).to_s(36)[0..7]

ajouter ljust si vous êtes vraiment paranoïaque sur la longueur de chaîne correcte:

 rand(2**256).to_s(36).ljust(8,'a')[0..7]
5
répondu user163365 2010-01-08 23:17:16

je pense que c'est un bel équilibre de concision, de clarté et de facilité de modification.

characters = ('a'..'z').to_a + ('A'..'Z').to_a
# Prior to 1.9, use .choice, not .sample
(0..8).map{characters.sample}.join

Facilement modifié

par exemple, y compris les chiffres:

characters = ('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a

uppercase hexadécimal:

characters = ('A'..'F').to_a + (0..9).to_a

Pour un impressionnant tableau de caractères:

characters = (32..126).to_a.pack('U*').chars.to_a
5
répondu Nathan Long 2012-02-23 20:34:38

j'ajoute juste mes sous ici...

def random_string(length = 8)
  rand(32**length).to_s(32)
end
5
répondu pduersteler 2012-07-16 02:22:00

vous pouvez utiliser String#random des facettes de rubis Gem facets :

https://github.com/rubyworks/facets/blob/126a619fd766bc45588cac18d09c4f1927538e33/lib/core/facets/string/random.rb

il fait fondamentalement ceci:

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
5
répondu Tilo 2014-08-22 22:53:52

mon préféré est (:A..:Z).to_a.shuffle[0,8].join . Notez que shuffle nécessite Ruby > 1.9.

4
répondu Josh 2013-11-28 18:18:17

Cette solution doit dépendance externe, mais semble plus jolie que l'autre.

  1. Installer le gem faker
  2. Faker::Lorem.characters(10) # => "ang9cbhoa8"
4
répondu asiniy 2015-09-18 16:12:49

:

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

simple expression, peut être passé comme argument, permet des caractères dupliqués:

Array.new(len) { chars.sample }.join
4
répondu Tim James 2017-08-31 09:56:55
''.tap {|v| 4.times { v << ('a'..'z').to_a.sample} }
3
répondu eric 2011-11-26 18:03:50

mes 2 cents:

  def token(length=16)
    chars = [*('A'..'Z'), *('a'..'z'), *(0..9)]
    (0..length).map {chars.sample}.join
  end
3
répondu tybro0103 2012-05-03 15:49:14

je viens d'écrire un petit bijou random_token pour générer des jetons pour la plupart des cas d'utilisation, profitez de ~

https://github.com/sibevin/random_token

3
répondu Sibevin Wang 2013-12-03 04:01:18

avec cette méthode, vous pouvez passer dans une longueur abitrary. Il est défini par défaut comme 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
2
répondu Ryan Bigg 2008-09-18 00:53:41

je préfère la réponse de Radar, jusqu'à présent, je pense.

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
répondu webmat 2008-09-18 02:35:00

je faisais quelque chose comme ça récemment pour générer une chaîne aléatoire de 8 octets à partir de 62 caractères. Les caractères étaient 0-9,A-z,A-Z. j'ai eu un tableau d'eux comme était boucle 8 fois et de choisir une valeur aléatoire hors du tableau. C'était dans une application de rails.

str = '' 8.times {|i| str << ARRAY_OF_POSSIBLE_VALUES[rand(SIZE_OF_ARRAY_OF_POSSIBLE_VALUES)] }

ce qui est bizarre, c'est que j'ai un bon nombre de copies. Maintenant, au hasard, cela devrait assez bien ne jamais arriver. 62 ^ 8 est énorme, mais sur 1200 codes environ dans la db i avait un bon nombre de doublons. Je les ai remarqués se produire sur les limites de l'heure l'un de l'autre. En d'autres termes, je pourrais voir un double à 12:12:23 2:12:22 ou quelque chose comme ça...Je ne sais pas si le temps est le problème ou non.

ce code était dans l'avant créer d'un objet activerecord. Avant la création de l'enregistrement, CE code s'exécutait et générait le code "unique". Les entrées dans le db étaient toujours produites de manière fiable, mais le code (str dans la ligne ci-dessus) était dupliqué beaucoup trop souvent.

j'ai créé un script pour exécuter 100000 itérations de cette ligne ci-dessus avec un petit délai de sorte qu'il faudrait 3-4 heures en espérant voir une sorte de motif de répétition sur une base horaire, mais n'a rien vu. Je n'ai aucune idée de pourquoi cela se passait dans mon application rails.

2
répondu erik 2010-08-07 20:16:09