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

Je suis actuellement en train de générer une chaîne majuscule pseudo-aléatoire 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 transmis en tant qu’argument, car il ne s’agit pas d’une seule déclaration. Pour obtenir une chaîne de caractères “a” .. “z” plus “A” .. “Z”, je l’ai changé pour:

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

mais ça ressemble à des ordures.

Est-ce que quelqu’un a une meilleure méthode?

 (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 un dernier qui est encore plus déroutant, mais plus souple et gaspille moins de cycles:

 o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten ssortingng = (0...50).map { o[rand(o.length)] }.join 

Pourquoi ne pas utiliser SecureRandom?

 require 'securerandom' random_ssortingng = SecureRandom.hex # outputs: 5b5cd0da3121fc53b4bc84d0c8af2e81 (ie 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

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

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

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

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 ssortingng from a set of easily readable characters def generate_activation_code(size = 6) charset = %w{ 2 3 4 6 7 9 ACDEFGHJKMNPQRTVWXYZ} (0...size).map{ charset.to_a[rand(charset.size)] }.join end 

D’autres ont mentionné quelque chose de similaire, mais cela utilise la fonction URL sécurisée.

 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 AZ, az, 0-9, “-” et “_”. “=” Est également utilisé si le remplissage est vrai.

 [*('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 IO)).sample(8).join 

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

Je ne me souviens plus où j’ai trouvé cela, mais cela me semble être le meilleur et le moins intensif:

 def random_ssortingng(length=10) chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789' password = '' length.times { password < < chars[rand(chars.size)] } password end 
 require 'securerandom' SecureRandom.urlsafe_base64(9) 

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

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

Il générera une chaîne aléatoire de longueur 2n contenant 0-9 et af

Depuis ruby ​​2.5 vraiment facile avec SecureRandom.alphanumeric :

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

Génère des chaînes aléatoires contenant AZ, az et 0-9 et devrait donc être applicable dans la plupart des cas d’utilisation. Et ils sont générés de manière aléatoire, ce qui pourrait être un avantage.


Edit: Un benchmark pour le comparer avec la solution ayant le plus de votes:

 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) 

La solution rand ne prend donc que les SecureRandom de SecureRandom . Peu importe si vous générez vraiment beaucoup de chaînes, mais si vous créez simplement une chaîne aléatoire de temps en temps, j’utiliserai toujours une implémentation plus sécurisée (car elle est également plus facile à appeler et plus explicite).

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 cette réponse

 require 'sha1' srand seed = "--#{rand(10000)}--#{Time.now}--" Digest::SHA1.hexdigest(seed)[0,8] 

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

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

Vous pouvez également l’utiliser pour un mot de passe aléatoire de longueur 8

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

J’espère que cela aidera et incroyable.

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" 

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 va aider.

Sachez que le rand est prévisible pour un attaquant et donc probablement non sécurisé. Vous devez absolument utiliser SecureRandom pour générer des mots de passe. J’utilise quelque chose comme ça:

 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 
 SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz') 

Quelque chose de Devise

Une autre méthode que j’aime utiliser

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

Ajoutez Ljust si vous êtes vraiment paranoïaque à propos de la longueur de chaîne correcte:

  rand(2**256).to_s(36).ljust(8,'a')[0..7] 

Je pense que c’est un bon compromis entre concision, clarté et 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 

Hexadécimal majuscule:

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

Pour un éventail de caractères vraiment impressionnant:

 characters = (32..126).to_a.pack('U*').chars.to_a 

Il suffit d’append mes cents ici …

 def random_ssortingng(length = 8) rand(32**length).to_s(32) end 

vous pouvez utiliser Ssortingng#random des facettes Facettes of Ruby Gem:

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

il fait essentiellement ceci:

 class Ssortingng 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 

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

Cette solution nécessite une dépendance externe, mais semble plus belle qu’une autre.

  1. Installez gem faker
  2. Faker::Lorem.characters(10) # => "ang9cbhoa8"

Donné:

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

L’expression unique, pouvant être transmise en tant qu’argument, autorise les doublons:

 Array.new(len) { chars.sample }.join 
 ''.tap {|v| 4.times { v < < ('a'..'z').to_a.sample} } 

Mes 2 centimes:

  def token(length=16) chars = [*('A'..'Z'), *('a'..'z'), *(0..9)] (0..length).map {chars.sample}.join end 

Je viens d’écrire un petit bijou random_token pour générer des jetons aléatoires pour la plupart des cas d’utilisation, profitez de ~

https://github.com/sibevin/random_token

Avec cette méthode, vous pouvez passer dans une longueur différente. Il est défini par défaut sur 6.

 def generate_random_ssortingng(length=6) ssortingng = "" chars = ("A".."Z").to_a length.times do ssortingng < < chars[rand(chars.length-1)] end string end 

J’aime mieux la réponse de Radar, jusqu’à présent, je pense. Je modifierais un peu comme ceci:

 CHARS = ('a'..'z').to_a + ('A'..'Z').to_a def rand_ssortingng(length=8) s='' length.times{ s < < CHARS[rand(CHARS.length)] } s end 

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, az, AZ. J’avais un tableau d’entre eux comme il était en boucle 8 fois et en choisissant une valeur aléatoire dans le tableau. C’était dans une application de rails.

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

La chose étrange est que j'ai eu un bon nombre de doublons. Maintenant, au hasard, cela ne devrait jamais se produire. 62 ^ 8 est énorme, mais sur environ 1200 codes dans la firebase database, j'avais un bon nombre de doublons. Je les ai remarqués se produire aux heures les uns des autres. En d'autres termes, je pourrais voir un dupe à 12:12:23 et 2:12:22 ou quelque chose comme ça… je ne sais pas si le temps est le problème ou pas.

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

J'ai créé un script pour parcourir 100 000 itérations de la ligne ci-dessus avec un léger retard, ce qui prendrait 3 à 4 heures dans l'espoir de voir un motif de répétition toutes les heures, mais sans rien voir. Je ne sais pas pourquoi cela se passait dans mon application rails.