2010-12-10 15 views
2

De une réponse StackOverflow je cette petite fonction propre à générer une chaîne de 10 caractères seulement az et 0-9 caractères: rand(36**10).to_s(36)Petit générateur de chaînes aléatoire qui malheureusement échoue parfois. S'il vous plaît aidez-moi à corriger

Le problème est qu'il échoue parfois et ne génère que 9 caractères . Mais j'aime vraiment la facilité et la vitesse de celui-ci. Avez-vous des suggestions pour le résoudre afin que je puisse être sûr qu'il génère toujours exactement 10 caractères? (Sans boucles ou de contrôle.)

+1

-t-il vraiment être aléatoire dans le sens que toute combinaison de lettres et de chiffres est également susceptible de venir? parce que ce n'est pas vraiment le cas. –

Répondre

5

Lorsque vous générer au hasard un nombre inférieur à 36 , il finit par être une chaîne de 9 caractères. Gauche-pad avec des zéros:

rand(36**10).to_s(36).rjust(10, "0") 

Exemple:

irb(main):018:0> (36**9).to_s(36) 
=> "1000000000" 
irb(main):019:0> (36**9 - 1).to_s(36) 
=> "zzzzzzzzz" 
irb(main):020:0> (36**5).to_s.rjust(10, "0") 
=> "0060466176" 
+0

Oui, cela fonctionnerait. La seule chose que je n'aime pas, c'est que c'est juste rempli ... pas vraiment aléatoire du tout. Ok, je pourrais le remplir avec quelques caractères aléatoires, mais ensuite je pourrais aussi générer chaque caractère par lui-même. – Zardoz

+0

@Zardos Qu'est-ce qui ne va pas avec le remplissage des zéros? (d'ailleurs vous ne l'aimez pas) .Un des 36 numéros commencera par un zéro; – steenslag

+1

@Zardoz: Si vous tentez d'obtenir une distribution uniforme de toutes les lettres et de tous les chiffres dans les 10 positions, alors votre approche est intrinsèquement erronée. Si vous voulez juste quelque chose de "aléatoire", suivez cette approche. Une meilleure approche vers l'uniformité serait de générer chaque caractère seul comme vous le suggérez. –

0

Cela va générer une chaîne aléatoire de caractères et de chiffres, mais pas un seul caractère apparaît plus d'une fois

(('a'..'z').to_a + (0..9).to_a).shuffle[1..10].join 

Pour « fixer » le nombre de résultats possibles que vous faites juste ceci:

a = (('a'..'z').to_a + (0..9).to_a) 
a = a * 10 
p a.shuffle[1..10].join 
+0

Est-ce que cela ne génèrerait pas juste une chaîne où chaque personnage peut être présent une seule fois ?! Cela réduirait beaucoup l'espace des résultats. – Zardoz

+0

oui il le ferait, vous obtiendrez 10333147966386144929666651337523200000000 combinaisons par opposition à beaucoup moins de 3656158440062976 avec votre méthode d'origine (sauf si je me trompe quelque chose) –

+0

désolé, je devais en effet mal calculer, avec ma méthode, vous auriez 16654322805120000 combinaisons –

0

Que diriez-vous:

>> require 'md5' 
=> true 
>> MD5::hexdigest(Time.now.to_f.to_s)[0..9] 
=> "89d83d3516" 
+1

n'est-ce pas juste un nombre hexadécimal? Je pense que le to_s (36) est censé générer toutes les lettres de a à z –

+3

non seulement cela, il va générer les mêmes valeurs s'il est appelé assez rapidement – Amnon

+0

Je cherche plus que des chaînes hexadécimales. Il devrait être possible d'utiliser chaque caractère en a-z et 0-9. – Zardoz

0

A partir de l'idée d'utiliser rand(36**5) par Rushakoff @ Mark, ce mélange le zéro chaîne rembourrée pour randomiser les caractères:

('%010x' % [rand(36**5)]).chars.to_a.shuffle.join # => "4a04020701" 
('%010x' % [rand(36**5)]).chars.to_a.shuffle.join # => "0e092f0a03" 
('%010x' % [rand(36**5)]).chars.to_a.shuffle.join # => "03e240e800" 

Pour contourner Ruby en n'autorisant pas les chaînes à remplissage nul dans le format Je dois passer au remplissage dans la chaîne de méthode, ce qui est essentiellement ce que Mark a fait. Pour éviter les chaînes de zéros en tête, le décomposer en un tableau et mélanger la chaîne et la rejoindre.

rand(36**5).to_s(36).rjust(10, '0').chars.to_a.shuffle.join # => "e80000h00b" 
rand(36**5).to_s(36).rjust(10, '0').chars.to_a.shuffle.join # => "00bv0dy00p" 
rand(36**5).to_s(36).rjust(10, '0').chars.to_a.shuffle.join # => "v0hw000092" 
+0

Il génère uniquement des nombres. Le rand de Mark génère non seulement des nombres mais aussi d'autres caractères (a-z, 0-9). – Zardoz

+0

Je l'ai modifié pour utiliser 0-9a-z. C'est un bon casse-tête pour voir si je peux obtenir la base (36) en utilisant 'format'. –

+0

Perl nous permet d'utiliser des chaînes à remplissage nul, mais il semble que Ruby ne le fasse pas. Les rats. Je soupçonne que c'est pourquoi @Mark Rushakoff est allé avec 'rjust'. –

0
(('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a).sample(8).join 
+1

Dans 1.9 '[*? A ..? Z, *? A ..? Z, * 0..9] .sample (8) .join' fait la même chose. –