it-swarm-eu.dev

Come generare una stringa casuale in Ruby

Attualmente sto generando una stringa maiuscola pseudo-casuale di 8 caratteri per "A" .. "Z":

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

ma non sembra pulito e non può essere passato come argomento poiché non è una singola istruzione. Per ottenere una stringa mista "a" .. "z" più "A" .. "Z", l'ho modificata in:

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

ma sembra spazzatura.

Qualcuno ha un metodo migliore?

702
Jeff
(0...8).map { (65 + Rand(26)).chr }.join

Trascorro troppo tempo giocando a golf.

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

E un ultimo che è ancora più confuso, ma più flessibile e spreca meno cicli:

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

Perché non usare SecureRandom?

require 'securerandom'
random_string = SecureRandom.hex

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

SecureRandom ha anche metodi per:

  • base64
  • random_bytes
  • numero casuale

vedi: http://Ruby-doc.org/stdlib-1.9.2/libdoc/securerandom/rdoc/SecureRandom.html

754

Lo uso per generare stringhe URL friendly con una lunghezza massima garantita:

Rand(36**length).to_s(36)

Genera stringhe casuali di minuscole a-z e 0-9. Non è molto personalizzabile ma è breve e pulito.

236

Questa soluzione genera una stringa di caratteri facilmente leggibili per i codici di attivazione; Non volevo che le persone confondessero 8 con B, 1 con I, 0 con O, L con 1, ecc.

# 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
165
ImNotQuiteJack

Altri hanno menzionato qualcosa di simile, ma utilizza la funzione di sicurezza dell'URL.

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

Il risultato può contenere A-Z, a-z, 0-9, "-" e "_". "=" È usato anche se il riempimento è vero.

124
Travis Reeder
[*('A'..'Z')].sample(8).join

Genera una stringa casuale di 8 lettere (ad esempio NVAYXHGR)

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

Genera una stringa casuale di 8 caratteri (ad esempio 3PH4SWF2), esclude 0/1/I/O. Rubino 1.9

45
Shai Coleman

Dato che Ruby 2.5 è davvero facile con SecureRandom.alphanumeric:

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

Genera stringhe casuali contenenti A-Z, a-z e 0-9 e pertanto dovrebbe essere applicabile nella maggior parte dei casi d'uso. E sono generati casualmente sicuri, il che potrebbe essere un vantaggio.


Modifica: un punto di riferimento per confrontarlo con la soluzione con i più 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)

Quindi la soluzione Rand impiega solo 3/4 del tempo di SecureRandom. Potrebbe importare se generi davvero molte stringhe, ma se crei qualche stringa casuale di tanto in tanto, utilizzerò sempre l'implementazione più sicura (dal momento che è anche più facile da chiamare e più esplicita).

34
Markus

Non riesco a ricordare dove ho trovato questo, ma mi sembra il processo migliore e meno intenso per me:

def random_string(length=10)
  chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
  password = ''
  length.times { password << chars[Rand(chars.size)] }
  password
end
30
Travis Reeder
require 'securerandom'
SecureRandom.urlsafe_base64(9)
27
LENZCOM

Se vuoi una stringa di lunghezza specificata, usa:

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

Genererà una stringa casuale di lunghezza 2n contenente 0-9 e a-f

24

Array.new(n){[*"0".."9"].sample}.join, dove n = 8 nel tuo caso.

Generalizzato: Array.new(n){[*"A".."Z", *"0".."9"].sample}.join, ecc. - da this answer

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

Ecco un codice semplice di una riga per stringa casuale con lunghezza 8

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

Puoi anche usarlo per password casuali di lunghezza 8

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

spero che sarà di aiuto e sorprendente.

10
Awais

Rubino 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
Ragmaanir

Essere consapevoli: Rand è prevedibile per un utente malintenzionato e quindi probabilmente insicuro. Dovresti sicuramente usare SecureRandom se questo è per generare password. Io uso qualcosa come questo:

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

Qualcosa di Devise

6
Thorpe Obazee

Aggiungo solo i miei centesimi qui ...

def random_string(length = 8)
  Rand(32**length).to_s(32)
end
5
pduersteler

puoi usare String#random dalle Facets di Ruby Gem facets:

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

fondamentalmente lo fa:

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
Tilo

Un altro metodo che mi piace usare

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

Aggiungi, se sei veramente paranoico sulla lunghezza della stringa corretta:

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

Penso che questo sia un buon equilibrio di concisione, chiarezza e facilità di modifica. 

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

Facilmente modificato

Ad esempio, includendo le cifre:

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

Esadecimale maiuscolo:

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

Per una serie di personaggi davvero impressionante:

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

Il mio preferito è (:A..:Z).to_a.shuffle[0,8].join. Nota che shuffle richiede Ruby> 1.9.

4
Josh

Questa soluzione ha bisogno di dipendenza esterna, ma sembra più carina di un'altra.

  1. Installa gemma faker
  2. Faker::Lorem.characters(10) # => "ang9cbhoa8"
4
asiniy

Dato:

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

Espressione singola, può essere passata come argomento, consente i caratteri duplicati:

Array.new(len) { chars.sample }.join
4
Tim James

I miei 2 centesimi:

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

Ho appena scritto una piccola gemma random_token per generare token casuali per la maggior parte dei casi d'uso, divertiti ~

https://github.com/sibevin/random_token

3
Sibevin Wang
''.tap {|v| 4.times { v << ('a'..'z').to_a.sample} }
3
eric

Stavo facendo qualcosa del genere di recente per generare una stringa casuale a 8 byte da 62 caratteri. I personaggi erano 0-9, a-z, A-Z. Ho avuto un array di loro come era il ciclo di 8 volte e prelevando un valore casuale dalla matrice. Questo era all'interno di un'app Rails.

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

La cosa strana è che ho ottenuto un buon numero di duplicati. Ora a caso questo dovrebbe praticamente non succedere mai. 62 ^ 8 è enorme, ma su 1200 o giù di lì i codici nel db ho avuto un buon numero di duplicati. Ho notato che accadono sui confini dell'ora l'uno dell'altro. In altre parole, potrei vedere un duple alle 12:12:23 e alle 2:12:22 o qualcosa del genere ... non sono sicuro che il tempo sia il problema o meno.

Questo codice era nella prima creazione di un oggetto activerecord. Prima della creazione del record, questo codice veniva eseguito e generava il codice "univoco". Le voci nel db sono sempre state prodotte in modo affidabile, ma il codice (str della riga precedente) veniva duplicato troppo spesso.

Ho creato uno script per eseguire 100000 iterazioni di questa riga sopra con un piccolo ritardo, quindi impiegheremmo 3-4 ore nella speranza di vedere qualche tipo di ripetizione su base oraria, ma non ho visto nulla. Non ho idea del perché questo stava accadendo nella mia app Rails.

3
erik

Se sei su UNIX e devi ancora usare Ruby 1.8 (no SecureRandom) senza Rails, puoi anche usare questo:

random_string = `openssl Rand -base64 24`

Nota che questo genera nuova shell, questo è molto lento e può essere raccomandato solo per gli script.

2
lzap

Un altro trucco che funziona con Ruby 1.8+ ed è veloce è:

>> require "openssl"
>> OpenSSL::Random.random_bytes(20).unpack('H*').join
=> "2f3ff53dd712ba2303a573d9f9a8c1dbc1942d28"

Si ottiene una stringa esadecimale casuale. In modo simile dovresti essere in grado di generare una stringa base64 ('M *').

2
lzap

La risposta di Radar mi piace di più, finora, penso. Mi piacerebbe modificare un po 'questo:

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
webmat

Il mio colpo migliore, 2 soluzioni per una stringa casuale composta da 3 gamme

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

([*(48..57),*(65..90),*(97..122)]).sample(8).collect(&:chr)*""
2
peter

provalo

def Rand_name(len=9)
  ary = [('0'..'9').to_a, ('a'..'z').to_a, ('A'..'Z').to_a]
  name = ''

  len.times do
    name << ary.choice.choice
  end
  name
end

Adoro le risposte del thread, sono stato molto utile, anzi !, ma se posso dire che nessuno di loro soddisfa i miei occhi, forse è il metodo Rand (). non mi sembra giusto, dal momento che abbiamo il metodo di scelta # di Array per quella materia.

2

Ecco un altro metodo:

  • Usa il generatore di numeri casuali sicuro invece di Rand ()
  • Può essere utilizzato in URL e nomi di file
  • Contiene caratteri maiuscoli, minuscoli e numeri
  • Ha un'opzione per non includere caratteri ambigui I0l01

Ha bisogno di require "securerandom"

def secure_random_string(length = 32, non_ambiguous = false)
  characters = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a

  %w{I O l 0 1}.each{ |ambiguous_character| 
    characters.delete ambiguous_character 
  } if non_ambiguous

  (0...length).map{
    characters[ActiveSupport::SecureRandom.random_number(characters.size)]
  }.join
end
2
Evgenii
10.times do 
  alphabet = ('a'..'z').to_a
  string += alpha[Rand(alpha.length)]
end
1
mminski

Questo si basa su poche altre risposte, ma aggiunge un po 'più di complessità:

def random_password
  specials = ((32..47).to_a + (58..64).to_a + (91..96).to_a + (123..126).to_a).pack('U*').chars.to_a
  numbers  = (0..9).to_a
  alpha    = ('a'..'z').to_a + ('A'..'Z').to_a
  %w{i I l L 1 O o 0}.each{ |ambiguous_character| 
    alpha.delete ambiguous_character 
  }
  characters = (alpha + specials + numbers)
  password = Random.new.Rand(8..18).times.map{characters.sample}
  password << specials.sample unless password.join =~ Regexp.new(Regexp.escape(specials.join))
  password << numbers.sample  unless password.join =~ Regexp.new(Regexp.escape(numbers.join))
  password.shuffle.join
end

In sostanza, garantisce una password di 8-20 caratteri e che contiene almeno un numero e un carattere speciale.

1
Chris Bloom

Per ideare secure_validatable puoi usare questo

(0 ... 8) .map {([65, 97] .sample + Rand (26)). Chr} .Push (Rand (99)).

1
shiva kumar

Ecco un miglioramento della risposta di @Travis R:

 def random_string(length=5)
    chars = 'abdefghjkmnpqrstuvwxyzABDEFGHJKLMNPQRSTUVWXYZ'
    numbers = '0123456789'
    random_s = ''
    (length/2).times { random_s << numbers[Rand(numbers.size)] }
    (length - random_s.length).times { random_s << chars[Rand(chars.size)] }
    random_s.split('').shuffle.join
  end

Alla risposta @Travis R i caratteri e i numeri erano uniti, quindi a volte random_string poteva restituire solo numeri o solo caratteri. Con questo miglioramento almeno la metà di random_string saranno i caratteri e il resto sono numeri. Nel caso avessi bisogno di una stringa casuale con numeri e caratteri

0
Lucas Andrade

Per rendere il primo in una dichiarazione:

(0...8).collect { |n| value  << (65 + Rand(25)).chr }.join()
0
Kevin Conner

Il modo più semplice è utilizzare la gemma string_pattern https://github.com/MarioRuiz/string_pattern

Ad esempio per generare 36 lettere casuali:

 require 'string_pattern'
 puts '36:L'.gen

Inoltre puoi usare le espressioni regolari

 require 'string_pattern'
 puts /[a-zA-Z]{36}/.gen
0
Mario Ruiz

Crea una stringa vuota o una pre-correzione se necessario:

myStr = "OID-"

Usa questo codice per compilare la stringa con numeri casuali:

begin; n = ((Rand * 43) + 47).ceil; myStr << n.chr if !(58..64).include?(n); end while(myStr.length < 12)

Gli appunti:

(Rand * 43) + 47).ceil

Genera numeri casuali da 48 a 91 (0,1,2..Y, Z)

!(58..64).include?(n)

È usato per saltare caratteri speciali (poiché non sono interessato a includerli)

while(myStr.length < 12)

Genererà una stringa lunga 12 caratteri, incluso il prefisso.

Uscita di esempio:

"OID-XZ2J32XM"
0
Ghazi
a='';8.times{a<<[*'a'..'z'].sample};p a

o

8.times.collect{[*'a'..'z'].sample}.join
0
Michael Kingski

Lo stiamo usando nel nostro codice:

class String

  def self.random(length=10)
    ('a'..'z').sort_by {Rand}[0,length].join
  end

end

La lunghezza massima supportata è 25 (lo usiamo solo con l'impostazione predefinita, quindi non è stato un problema).

Qualcuno ha detto che "a" .. "z" è subottimale se si vuole evitare completamente di generare parole offensive. Una delle idee che avevamo era la rimozione delle vocali, ma si finisce comunque con WTFBBQ ecc.

0
Carlos Villela
`pwgen 8 1`.chomp
0
Nathan L Smith

Ecco una soluzione che è flessibile e consente dups:

class String
  # generate a random string of length n using current string as the source of characters
  def random(n)
    return "" if n <= 0
    (chars * (n / length + 1)).shuffle[0..n-1].join  
  end
end

Esempio:

"ATCG".random(8) => "CGTGAAGA"

Puoi anche consentire a un determinato personaggio di apparire più frequentemente:

"AAAAATCG".random(10) => "CTGAAAAAGC"

Spiegazione: Il metodo precedente prende i caratteri di una determinata stringa e genera una matrice abbastanza grande. Quindi lo rimescola, prende i primi n elementi, quindi li unisce.

0
Abdo
Array.new(8).inject(""){|r|r<<('0'..'z').to_a.shuffle[0]}  # 57
(1..8).inject(""){|r|r<<('0'..'z').to_a.shuffle[0]}        # 51
e="";8.times{e<<('0'..'z').to_a.shuffle[0]};e              # 45
(1..8).map{('0'..'z').to_a.shuffle[0]}.join                # 43
(1..8).map{Rand(49..122).chr}.join                         # 34
0
Automatico

Usa gemma 'SafeRandom' GithubLink

Fornirà il modo più semplice per generare valori casuali per Rails2, Rails 3, Rails 4, Rails 5 compatibili. 

0
Rubyist