Cómo generar una cadena aleatoria en Ruby


Actualmente estoy generando una cadena pseudo-aleatoria en mayúsculas de 8 caracteres para "A" .. "Z":

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

Pero no se ve limpio, y no se puede pasar como un argumento ya que no es una sola declaración. Para obtener una cadena de mayúsculas y minúsculas "a".. "z" más "A".. "Z", lo cambié a:

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

Pero parece basura.

¿alguien tiene un método mejor?

Author: Jeff, 2008-09-18

30 answers

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

Paso demasiado tiempo jugando al golf.

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

Y una última que es aún más confusa, pero más flexible y desperdicia menos ciclos:

o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten
string = (0...50).map { o[rand(o.length)] }.join
 885
Author: Kent Fredric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-09 10:56:00

¿Por qué no usar SecureRandom?

require 'securerandom'
random_string = SecureRandom.hex

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

SecureRandom también tiene métodos para:

  • base64
  • random_bytes
  • random_number

Véase: http://ruby-doc.org/stdlib-1.9.2/libdoc/securerandom/rdoc/SecureRandom.html

 744
Author: christopherstyles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-04 20:07:47

Uso esto para generar cadenas aleatorias amigables con URL con una longitud máxima garantizada:

rand(36**length).to_s(36)

Genera cadenas aleatorias de a-z minúsculas y 0-9. No es muy personalizable, pero es corto y limpio.

 230
Author: Christoffer Möller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-04 08:37:57

Esta solución genera una cadena de caracteres fácilmente legibles para los códigos de activación; no quería que la gente confundiera 8 con B, 1 con I, 0 con O, L con 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
 163
Author: 2 revs, 2 users 86%ImNotQuiteJack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-25 00:32:31

Otros han mencionado algo similar, pero esto usa la función 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=="

El resultado puede contener a-Z, a-z, 0-9, "-" y "_". "="también se usa si el relleno es verdadero.

 120
Author: Travis R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-05-16 19:40:12
[*('A'..'Z')].sample(8).join

Generar una cadena aleatoria de 8 letras (por ejemplo, NVAYXHGR)

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

Generar una cadena aleatoria de 8 caracteres (por ejemplo, 3PH4SWF2), excluye 0/1 / I / O. Ruby 1.9

 44
Author: Tom Carr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-22 11:58:53

No puedo recordar dónde encontré esto, pero me parece el mejor y el menos intensivo proceso:

def random_string(length=10)
  chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
  password = ''
  length.times { password << chars[rand(chars.size)] }
  password
end
 30
Author: Travis R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-24 22:41:44
require 'securerandom'
SecureRandom.urlsafe_base64(9)
 27
Author: LENZCOM,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-13 00:34:57

Desde ruby 2.5 realmente fácil con SecureRandom.alphanumeric:

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

Genera cadenas aleatorias que contienen A-Z, a-z y 0-9 y, por lo tanto, debería ser aplicable en la mayoría de los casos de uso. Y se generan aleatoriamente seguros, lo que también podría ser un beneficio.


Editar: Un punto de referencia para compararlo con la solución que tiene más votos positivos:

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)

Así que la solución rand solo toma alrededor de 3/4 del tiempo de SecureRandom. Podría importar si generas realmente un montón de cadenas, pero si simplemente cree alguna cadena aleatoria de vez en cuando Siempre iría con la implementación más segura (ya que también es más fácil de llamar y más explícita).

 25
Author: Markus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-30 12:39:47

Si desea una cadena de longitud especificada, use:

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

Generará una cadena aleatoria de longitud 2n que contiene 0-9 y a-f

 24
Author: Srikanta Mahapatro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-15 09:28:29

Array.new(n){[*"0".."9"].sample}.join, donde n = 8 en su caso.

Generalizado: Array.new(n){[*"A".."Z", *"0".."9"].sample}.join, etc. - de esta respuesta

 13
Author: gr8scott06,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:59
require 'sha1'
srand
seed = "--#{rand(10000)}--#{Time.now}--"
Digest::SHA1.hexdigest(seed)[0,8]
 11
Author: Coren,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-17 22:40:34

Aquí hay un código simple de línea para cadena aleatoria con longitud 8

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

También puede usarlo para contraseñas aleatorias que tengan una longitud 8

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

Espero que ayude y sorprendente.

 10
Author: Awais,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-19 06:12:15

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"
 10
Author: Ragmaanir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-13 15:04:26

Aquí hay un código simple para la contraseña aleatoria con lenth 8

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

Espero que ayude.

 8
Author: Thaha kp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-15 06:51:24

Tenga en cuenta: rand es predecible para un atacante y, por lo tanto, probablemente inseguro. Definitivamente debe usar SecureRandom si esto es para generar contraseñas. Yo uso algo como esto:

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
Author: pencil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-03-30 14:30:32
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')

Algo de Devise

 6
Author: Thorpe Obazee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-19 00:25:43

Otro método que me gusta usar

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

Agregue ljust si usted es realmente paranoico acerca de la longitud correcta de la cadena:

 rand(2**256).to_s(36).ljust(8,'a')[0..7]
 5
Author: user163365,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-08 23:17:16

Creo que este es un buen equilibrio de concisión, claridad y facilidad de modificación.

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

Fácilmente modificable

Por ejemplo, incluyendo dígitos:

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

Hexadecimal en mayúsculas:

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

Para una impresionante variedad de personajes:

characters = (32..126).to_a.pack('U*').chars.to_a
 5
Author: Nathan Long,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-23 20:34:38

Solo sumando mis centavos aquí...

def random_string(length = 8)
  rand(32**length).to_s(32)
end
 5
Author: pduersteler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-16 02:22:00

Puedes usar String#random de las Facetas de Ruby Gem facets:

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

Básicamente hace esto:

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
Author: Tilo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-22 22:53:52

Mi favorito es (:A..:Z).to_a.shuffle[0,8].join. Tenga en cuenta que shuffle requiere Ruby > 1.9.

 4
Author: Josh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-28 18:18:17

Esta solución necesita dependencia externa, pero parece más bonita que otra.

  1. Instalar gem faker
  2. Faker::Lorem.characters(10) # => "ang9cbhoa8"
 4
Author: asiniy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-18 16:12:49

Dado:

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

Expresión única, se puede pasar como argumento, permite caracteres duplicados:

Array.new(len) { chars.sample }.join
 4
Author: Tim James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-31 09:56:55
''.tap {|v| 4.times { v << ('a'..'z').to_a.sample} }
 3
Author: eric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-26 18:03:50

Mis 2 centavos:

  def token(length=16)
    chars = [*('A'..'Z'), *('a'..'z'), *(0..9)]
    (0..length).map {chars.sample}.join
  end
 3
Author: tybro0103,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-03 15:49:14

Acabo de escribir una pequeña gema random_token para generar tokens aleatorios para la mayoría de los casos de uso, enjoy ~

Https://github.com/sibevin/random_token

 3
Author: Sibevin Wang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-03 04:01:18

Con este método se puede pasar una longitud abitraria. Se establece como valor predeterminado 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
 2
Author: Ryan Bigg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-18 00:53:41

Me gusta más la respuesta de Radar, hasta ahora, creo. Me gustaría ajustar un poco como esto:

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
Author: webmat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-18 02:35:00

Estaba haciendo algo como esto recientemente para generar una cadena aleatoria de 8 bytes a partir de 62 caracteres. Los caracteres eran 0-9, a-z, A-Z. Tenía una matriz de ellos como looping 8 veces y eligiendo un valor aleatorio de la matriz. Esto estaba dentro de una aplicación rails.

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

Lo raro es que tengo un buen número de duplicados. Ahora, al azar, esto casi nunca debería suceder. 62^8 es enorme, pero de 1200 más o menos códigos en la base de datos que tenía un buen número de duplicados. Me di cuenta ellos pasando en los límites de hora uno de otro. En otras palabras, podría ver una dupla a las 12:12:23 y 2: 12: 22 o algo así...no estoy seguro de si el tiempo es el problema o no.

Este código estaba en la creación anterior de un objeto activerecord. Antes de que se creara el registro, este código se ejecutaría y generaría el código 'único'. Las entradas en la base de datos siempre se producían de forma fiable, pero el código (str en la línea anterior) se duplicaba con demasiada frecuencia.

He creado un script para ejecutar 100000 iteraciones de esta línea anterior con un pequeño retraso por lo que tomaría 3-4 horas con la esperanza de ver algún tipo de patrón de repetición sobre una base horaria, pero no vio nada. No tengo ni idea de por qué estaba pasando esto en mi aplicación rails.

 2
Author: erik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-07 20:16:09