Come generare una stringa casuale in Ruby
Domanda
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 "a" composta da maiuscole e minuscole .."z" più "A"..."Z", l'ho cambiato in:
value = ""; 8.times{value << ((rand(2)==1?65:97) + rand(25)).chr}
ma sembra spazzatura.
Qualcuno ha un metodo migliore?
Soluzione
(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'ultima ancora più confusa, ma più flessibile e che spreca meno cicli:
o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten
string = (0...50).map { o[rand(o.length)] }.join
Altri suggerimenti
Perché non utilizzare SecureRandom?
require 'securerandom'
random_string = SecureRandom.hex
# outputs: 5b5cd0da3121fc53b4bc84d0c8af2e81 (i.e. 32 chars of 0..9, a..f)
SecureRandom dispone anche di metodi per:
- base64
- byte_casuali
- numero casuale
Vedere: http://ruby-doc.org/stdlib-1.9.2/libdoc/securerandom/rdoc/SecureRandom.html
Lo uso per generare stringhe URL friendly casuali con una lunghezza massima garantita:
rand(36**length).to_s(36)
Genera stringhe casuali di lettere minuscole a-z e 0-9.Non è molto personalizzabile ma è breve e pulito.
Questa soluzione genera una stringa di caratteri facilmente leggibili per i codici di attivazione;Non volevo che la gente confondesse 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
Altri hanno menzionato qualcosa di simile, ma questo utilizza la funzione URL sicura.
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 “_”.“=" viene utilizzato anche se il riempimento è vero.
[*('A'..'Z')].sample(8).join
Genera una stringa casuale di 8 lettere (es.NVAYXHGR)
([*('A'..'Z'),*('0'..'9')]-%w(0 1 I O)).sample(8).join
Genera una stringa casuale di 8 caratteri (es.3PH4SWF2), esclude 0/1/I/O.Rubino 1.9
Dal momento che Ruby 2.5 è davvero facile 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 vengono generati in modo casuale e sicuro, il che potrebbe essere anche un vantaggio.
Modificare:Un benchmark per confrontarlo con la soluzione con più voti positivi:
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)
Così il rand
la soluzione richiede solo circa 3/4 del tempo SecureRandom
.Potrebbe avere importanza se generi davvero molte stringhe, ma se crei solo qualche stringa casuale di tanto in tanto, opterei sempre per l'implementazione più sicura (poiché è anche più facile da chiamare e più esplicita).
Non riesco a ricordare dove l'ho trovato, ma mi sembra il migliore e il meno impegnativo in termini di processo:
def random_string(length=10)
chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
password = ''
length.times { password << chars[rand(chars.size)] }
password
end
require 'securerandom'
SecureRandom.urlsafe_base64(9)
Se vuoi una stringa della lunghezza specificata, usa:
require 'securerandom'
randomstring = SecureRandom.hex(n)
Genererà una stringa casuale di lunghezza 2n
contenente 0-9
E a-f
Array.new(n){[*"0".."9"].sample}.join
, dove n = 8 nel tuo caso.
Generalizzato: Array.new(n){[*"A".."Z", *"0".."9"].sample}.join
, eccetera.- da Questo risposta
require 'sha1'
srand
seed = "--#{rand(10000)}--#{Time.now}--"
Digest::SHA1.hexdigest(seed)[0,8]
Ecco un semplice codice di una riga per una 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 possa essere d'aiuto e fantastico.
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"
Ecco un semplice codice per una password casuale con lunghezza 8
rand_password=('0'..'z').to_a.shuffle.first(8).join
Spero che possa essere d'aiuto.
Essere consapevoli: rand
è prevedibile per un utente malintenzionato e quindi probabilmente insicuro.Dovresti assolutamente usare SecureRandom se serve per generare password.Io uso qualcosa del genere:
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
Un altro metodo che mi piace usare
rand(2**256).to_s(36)[0..7]
Aggiungi ljust se sei davvero paranoico riguardo alla lunghezza corretta della stringa:
rand(2**256).to_s(36).ljust(8,'a')[0..7]
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
Qualcosa da Devise
Penso che questo sia un buon equilibrio tra 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 modificabile
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 gamma di personaggi davvero impressionante:
characters = (32..126).to_a.pack('U*').chars.to_a
Aggiungo solo i miei centesimi qui...
def random_string(length = 8)
rand(32**length).to_s(32)
end
Puoi usare String#random
dalle sfaccettature della gemma rubino facets
:
sostanzialmente fa questo:
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
Il mio preferito è (:A..:Z).to_a.shuffle[0,8].join
.Tieni presente che la riproduzione casuale richiede Ruby > 1.9.
Questa soluzione necessita di dipendenza esterna, ma sembra più carina di un'altra.
- Installa la gemma falso
Faker::Lorem.characters(10) # => "ang9cbhoa8"
Dato:
chars = [*('a'..'z'),*('0'..'9')].flatten
L'espressione singola, che può essere passata come argomento, consente caratteri duplicati:
Array.new(len) { chars.sample }.join
Recentemente stavo facendo qualcosa del genere per generare una stringa casuale di 8 byte da 62 caratteri.I caratteri erano 0-9,a-z,A-Z.Ne avevo un array mentre eseguivo il loop 8 volte e sceglievo un valore casuale dall'array.Questo era all'interno di un'app ferroviaria.
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, casualmente, questo non dovrebbe praticamente mai accadere.62 ^ 8 è enorme, ma su circa 1200 codici nel db ho avuto un buon numero di duplicati.Ho notato che accadevano a intervalli di ore l'uno dall'altro.In altre parole, potrei vedere un doppio alle 12:12:23 e alle 2:12:22 o qualcosa del genere... non sono sicuro se il problema sia il tempo o meno.
Questo codice era presente prima della creazione di un oggetto activerecord.Prima che il record fosse creato, questo codice veniva eseguito e generava il codice "univoco".Le voci nel db venivano sempre prodotte in modo affidabile, ma il codice (str nella riga sopra) veniva duplicato troppo spesso.
Ho creato uno script per eseguire 100.000 iterazioni di questa riga sopra con un piccolo ritardo, quindi ci vorrebbero 3-4 ore sperando di vedere una sorta di schema di ripetizione su base oraria, ma non ho visto nulla.Non ho idea del motivo per cui ciò accadesse nella mia app Rails.
''.tap {|v| 4.times { v << ('a'..'z').to_a.sample} }
I miei 2 centesimi:
def token(length=16)
chars = [*('A'..'Z'), *('a'..'z'), *(0..9)]
(0..length).map {chars.sample}.join
end
Scrivo solo un piccolo gioiello random_token
per generare token casuali per la maggior parte dei casi d'uso, divertiti con ~
Con questo metodo puoi passare in una lunghezza arbitraria.È impostato come predefinito su 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
Penso che finora mi piaccia di più la risposta di Radar.Io modificherei un po' così:
CHARS = ('a'..'z').to_a + ('A'..'Z').to_a
def rand_string(length=8)
s=''
length.times{ s << CHARS[rand(CHARS.length)] }
s
end