Question

Je génère actuellement une chaîne majuscule pseudo-aléatoire de 8 caractères pour "A" .."Z":

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

mais cela n'a pas l'air clair et cela ne peut pas être passé comme argument puisqu'il ne s'agit pas d'une seule instruction.Pour obtenir une chaîne à casse mixte "a" .."z" plus "A" .."Z", je l'ai changé en :

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

mais ça ressemble à une poubelle.

Quelqu'un a-t-il une meilleure méthode ?

Était-ce utile?

La solution

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

Je passe trop de temps à jouer au golf.

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

Et un dernier qui est encore plus déroutant, mais plus flexible et qui gaspille moins de cycles:

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

Autres conseils

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
  • numéro_aléatoire

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 adaptées aux URL 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.

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

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

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, & # 8220; - & # 8221; et & # 8220; _ & # 8221 ;. & # 8220; = & # 8221; 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 I O)).sample(8).join

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

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 de manière aléatoire et sécurisée, ce qui pourrait également être un avantage.


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

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)

Alors le rand la solution ne prend qu'environ 3/4 du temps de SecureRandom.Cela peut avoir de l'importance si vous générez beaucoup de chaînes, mais si vous créez simplement une chaîne aléatoire de temps en temps, j'opterais toujours pour l'implémentation la plus sécurisée (car elle est également plus facile à appeler et plus explicite).

Je ne me souviens pas où j'ai trouvé cela, mais cela me semble être le meilleur et le moins intensif en processus:

def random_string(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'
randomstring = SecureRandom.hex(n)

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

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 à une ligne pour une chaîne aléatoire de longueur 8

 random_string = ('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 ça va aider 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 cela aidera.

Attention: rand est prévisible pour un attaquant et donc probablement non sécurisé. Vous devez absolument utiliser SecureRandom s'il s'agit de 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

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

Quelque chose de Devise

Je pense que c'est un bon équilibre 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 nombre de caractères vraiment impressionnant:

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

Ajoutez simplement mes centimes ici ...

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

vous pouvez utiliser String#random à partir des facettes de Ruby Gem facets:

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

il fait essentiellement 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

Mon favori est (:A..:Z).to_a.shuffle[0,8].join. Notez que shuffle nécessite Ruby & Gt; 1.9.

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

  1. Installer un bijou faker
  2. Faker::Lorem.characters(10) # => "ang9cbhoa8"

Donné:

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

Une seule expression, pouvant être passée en argument, autorise les caractères en double:

Array.new(len) { chars.sample }.join

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'avais un tableau d'entre eux en boucle 8 fois et en sélectionnant une valeur aléatoire dans le tableau. C'était à l'intérieur d'une application rails.

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

Ce qui est étrange, c’est que j’ai reçu un bon nombre de doublons. Maintenant, au hasard, cela ne devrait pratiquement jamais arriver. 62 ^ 8 est énorme, mais sur environ 1200 codes de la base de données, j'ai eu un bon nombre de doublons. J'ai remarqué qu'ils se passaient à la limite d'une heure. En d'autres termes, je pourrais voir un duple à 12:12:23 et 2:12:22 ou quelque chose du genre ... je ne suis pas sûr que le temps soit au rendez-vous ou non.

Ce code était dans le précédent créer un objet activerecord. Avant la création de l'enregistrement, ce code était exécuté et générait le code "unique". Les entrées dans la base de données é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 permettant d'exécuter 100 000 itérations de cette ligne ci-dessus avec un léger retard, de sorte que cela prendrait 3-4 heures dans l'espoir de voir une sorte de motif de répétition heure par heure, mais rien ne se voyait. Je ne sais pas pourquoi cela se passait dans mon application rails.

''.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 une petite pierre précieuse random_token pour générer des jetons aléatoires dans la plupart des cas d'utilisation, profitez de ~

https://github.com/sibevin/random_token

Avec cette méthode, vous pouvez transmettre une longueur arbitraire. Il est défini par défaut sur 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

J'aime mieux la réponse de Radar, jusqu'à présent, je pense. Je peaufine un peu comme ça:

CHARS = ('a'..'z').to_a + ('A'..'Z').to_a
def rand_string(length=8)
  s=''
  length.times{ s << CHARS[rand(CHARS.length)] }
  s
end
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top