Como gerar uma seqüência aleatória em Ruby
Pergunta
Atualmente estou gerando uma cadeia de caracteres em maiúsculas pseudo-aleatório de 8 caracteres para "A" .. "Z":
value = ""; 8.times{value << (65 + rand(25)).chr}
mas não parece limpo, e não pode ser passado como um argumento, uma vez que não é uma única instrução. Para obter uma seqüência de letras maiúsculas e minúsculas "a" .. "z" plus "A" .. "Z", o texto foi alterado para:
value = ""; 8.times{value << ((rand(2)==1?65:97) + rand(25)).chr}
mas parece que lixo.
Alguém tem um método melhor?
Solução
(0...8).map { (65 + rand(26)).chr }.join
I gastar muito golfe tempo.
(0...50).map { ('a'..'z').to_a[rand(26)] }.join
E a última que é ainda mais confuso, mas mais flexíveis e desperdiça menos ciclos:
o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten
string = (0...50).map { o[rand(o.length)] }.join
Outras dicas
Por que não usar SecureRandom?
require 'securerandom'
random_string = SecureRandom.hex
# outputs: 5b5cd0da3121fc53b4bc84d0c8af2e81 (i.e. 32 chars of 0..9, a..f)
SecureRandom também tem métodos para:
- base64
- random_bytes
- random_number
ver: http: // ruby-doc. org / stdlib-1.9.2 / libdoc / SecureRandom / rdoc / SecureRandom.html
Eu uso isso para a geração de cordas amigáveis ??URL aleatória com um comprimento máximo garantido:
rand(36**length).to_s(36)
Ele gera cadeias aleatórias de um-z minúsculas e 0-9. Não é muito personalizável, mas é curto e limpo.
Esta solução gera uma cadeia de caracteres facilmente legíveis para códigos de ativação; Eu não queria que as pessoas confusas 8 com B, 1 com I, 0 com O, L com 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
Outros mencionaram algo semelhante, mas este usa a função segura URL.
require 'securerandom'
p SecureRandom.urlsafe_base64(5) #=> "UtM7aa8"
p SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
p SecureRandom.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="
O resultado pode conter A-Z, um-z, 0-9, “-” e “_”. “=” Também é usado se o preenchimento é verdade.
[*('A'..'Z')].sample(8).join
Gerar um aleatória 8 carta string (por exemplo NVAYXHGR)
([*('A'..'Z'),*('0'..'9')]-%w(0 1 I O)).sample(8).join
Gerar um aleatória 8 cadeia de caracteres (por exemplo 3PH4SWF2), exclui 0/1 / I / O. Ruby 1.9
Desde rubi 2,5 realmente fácil com SecureRandom.alphanumeric
:
len = 8
SecureRandom.alphanumeric(len)
=> "larHSsgL"
Gera cadeias aleatórias que contenham A-Z, um-z e 0-9 e, por conseguinte, deve ser aplicável na maioria dos casos de utilização. E eles são gerados aleatoriamente seguro, que pode ser um benefício, também.
Edit: Uma referência para compará-lo com a solução de ter a maioria dos 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)
Portanto, a solução rand
só leva cerca de 3/4 do tempo de SecureRandom
. Pode importa se você gerar realmente um monte de cordas, mas se você apenas criar alguma seqüência aleatória de tempos em tempos eu sempre ir com a implementação mais segura (uma vez que também é mais fácil de chamar e mais explícita).
Não me lembro onde eu encontrei isso, mas parece que o melhor eo menos intenso processo para mim:
def random_string(length=10)
chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
password = ''
length.times { password << chars[rand(chars.size)] }
password
end
require 'securerandom'
SecureRandom.urlsafe_base64(9)
Se você quer uma cadeia de comprimento especificado, use:
require 'securerandom'
randomstring = SecureRandom.hex(n)
Ele irá gerar uma seqüência aleatória de 2n
comprimento contendo 0-9
e a-f
Array.new(n){[*"0".."9"].sample}.join
,
onde n = 8 no seu caso.
generalizada: Array.new(n){[*"A".."Z", *"0".."9"].sample}.join
, etc. - de este resposta
require 'sha1'
srand
seed = "--#{rand(10000)}--#{Time.now}--"
Digest::SHA1.hexdigest(seed)[0,8]
Aqui está um código simples uma linha para seqüência aleatória com comprimento de 8
random_string = ('0'..'z').to_a.shuffle.first(8).join
Você também pode usá-lo para a senha aleatória com comprimento de 8
random_password = ('0'..'z').to_a.shuffle.first(8).join
Espero que ele vai ajudar e surpreendente.
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"
Aqui está um código simples para senhas aleatórias com comprimento de 8
rand_password=('0'..'z').to_a.shuffle.first(8).join
Hope ele vai ajudar.
Esteja ciente: rand
é previsível para um atacante e, portanto, provavelmente inseguro. Você deve definitivamente usar SecureRandom se isto é para gerar senhas. Eu uso algo como isto:
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
Outro método que eu gosto de usar
rand(2**256).to_s(36)[0..7]
Adicionar ljust se você for realmente paranóico sobre o comprimento da corda correto:
rand(2**256).to_s(36).ljust(8,'a')[0..7]
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
Algo de Devise
Eu acho que este é um bom equilíbrio de concisão, clareza e facilidade de modificação.
characters = ('a'..'z').to_a + ('A'..'Z').to_a
# Prior to 1.9, use .choice, not .sample
(0..8).map{characters.sample}.join
facilmente modificado
Por exemplo, incluindo dígitos:
characters = ('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a
Maiúsculas hexadecimal:
characters = ('A'..'F').to_a + (0..9).to_a
Para uma matriz verdadeiramente impressionante de personagens:
characters = (32..126).to_a.pack('U*').chars.to_a
Basta adicionar meus centavos aqui ...
def random_string(length = 8)
rand(32**length).to_s(32)
end
Você pode usar String#random
das facetas do Ruby Gem facets
:
que basicamente faz isso:
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
O meu favorito é (:A..:Z).to_a.shuffle[0,8].join
. Note-se que shuffle requer Rubi> 1.9.
Esta solução precisa de dependência externa, mas parece mais bonita que a outra.
- Instale gem faker
-
Faker::Lorem.characters(10) # => "ang9cbhoa8"
Dada:
chars = [*('a'..'z'),*('0'..'9')].flatten
expressão única, pode ser passado como um argumento, permite caracteres duplicados:
Array.new(len) { chars.sample }.join
Eu estava fazendo algo parecido com isto recentemente para gerar uma seqüência aleatória de 8 bytes de 62 caracteres. Os caracteres foram 0-9, um-z, A-Z. Eu tive uma série de-los como foi looping 8 vezes e escolher um valor aleatório para fora da matriz. Este estava dentro de uma app Rails.
str = ''
8.times {|i| str << ARRAY_OF_POSSIBLE_VALUES[rand(SIZE_OF_ARRAY_OF_POSSIBLE_VALUES)] }
O estranho é que eu tenho bom número de duplicatas. Agora aleatoriamente esta praticamente nunca deveria acontecer. 62 ^ 8 é enorme, mas fora de 1200 ou assim códigos no db i teve um bom número de duplicatas. Notei-los acontecendo em limites hora um do outro. Em outras palavras eu poderia ver um duple em 0:12:23 e 2:12:22, ou algo assim ... não tenho certeza se o tempo é a questão ou não.
Este código estava no antes de criar de um objeto activerecord. Antes do registro foi criado este código seria executado e gerar o código 'único'. Entradas no db foram sempre produzidos de forma confiável, mas o código (str na linha acima) estava sendo duplicado com muita freqüência.
Eu criei um script para ser executado através de 100000 iterações desta linha acima com pequeno atraso de modo que levaria 3-4 horas esperando para ver algum tipo de padrão de repetição numa base horária, mas não viu nada. Eu não tenho idéia por que isso estava acontecendo na minha rails aplicativo.
''.tap {|v| 4.times { v << ('a'..'z').to_a.sample} }
Meus 2 centavos:
def token(length=16)
chars = [*('A'..'Z'), *('a'..'z'), *(0..9)]
(0..length).map {chars.sample}.join
end
Eu só escrever um pequeno random_token
gem para gerar tokens aleatórios para mais casos de uso, desfrutar ~
Com este método você pode passar em um comprimento arbitrário. É definido como um padrão como 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
Eu gosto de resposta de Radar melhor, até agora, eu acho. Eu ajustar um pouco como este:
CHARS = ('a'..'z').to_a + ('A'..'Z').to_a
def rand_string(length=8)
s=''
length.times{ s << CHARS[rand(CHARS.length)] }
s
end