Jak wygenerować losowy ciąg znaków w Ruby

Obecnie generuję 8-znakowy pseudolosowy ciąg wielkich liter dla "A".. "Z": {]}

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

Ale nie wygląda to na czyste i nie może być przekazane jako argument, ponieważ nie jest pojedynczą instrukcją. Aby uzyskać mieszany ciąg znaków "a".. "z" plus "A".. "Z", zmieniłem na:

value = ""; 8.times{value << ((rand(2)==1?65:97) + rand(25)).chr}
Ale wygląda jak śmieć. Czy ktoś ma lepszą metodę?
Author: Jeff, 2008-09-18

30 answers

(0...8).map { (65 + rand(26)).chr }.join
Za dużo czasu spędzam na golfie.
(0...50).map { ('a'..'z').to_a[rand(26)] }.join
I ostatni, który jest jeszcze bardziej zagmatwany, ale bardziej elastyczny i marnuje mniej cykli:]}
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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-09 10:56:00

Dlaczego nie użyć SecureRandom?

require 'securerandom'
random_string = SecureRandom.hex

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

SecureRandom ma również metody dla:

  • base64
  • random_bytes
  • random_number

Zobacz: 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-04 20:07:47

Używam tego do generowania losowych łańcuchów przyjaznych URL o gwarantowanej maksymalnej długości:

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

Generuje losowe ciągi małych liter a-z i 0-9. Nie jest zbyt konfigurowalny, ale jest krótki i czysty.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-04 08:37:57

To rozwiązanie generuje ciąg łatwych do odczytania znaków dla kodów aktywacyjnych; nie chciałem, aby ludzie mylili 8 z B, 1 z I, 0 Z O, L z 1, itd.

# 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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-25 00:32:31

Inni wspominali o czymś podobnym, ale używa To funkcji 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=="

Wynik może zawierać A-Z, A-Z, 0-9, " - "i"_". "="jest również używany, jeśli wypełnienie jest prawdziwe.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-16 19:40:12
[*('A'..'Z')].sample(8).join

Wygeneruj losowy ciąg 8 liter (np. NVAYXHGR)

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

Wygenerować losowy ciąg 8 znaków (np. 3PH4SWF2), wyłączając 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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-22 11:58:53

Nie pamiętam, gdzie to znalazłem, ale wydaje mi się, że jest to najlepsze i najmniej intensywne procesowo:

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/doraprojects.net/template/agent.layouts/content.php on line 54
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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-13 00:34:57

Od ruby 2.5 naprawdę łatwo z SecureRandom.alphanumeric:

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

Generuje losowe łańcuchy zawierające A-Z, a-Z i 0-9 i dlatego powinny być stosowane w większości przypadków. I są one generowane losowo bezpieczne, co może być również korzyścią.


Edit: benchmark do porównania go z rozwiązaniem mającym najwięcej 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)

Więc rozwiązanie rand zajmuje tylko około 3/4 czasu SecureRandom. Może mieć znaczenie, jeśli generujesz naprawdę dużo ciągów, ale jeśli wystarczy stworzyć jakiś losowy ciąg znaków od czasu do czasu zawsze wybierałbym bardziej bezpieczną implementację (ponieważ jest również łatwiejsze do wywołania i bardziej wyraźne).

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-30 12:39:47

Jeśli chcesz ciąg o określonej długości, użyj:

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

Wygeneruje losowy ciąg o długości 2n zawierający 0-9 i 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-15 09:28:29

Array.new(n){[*"0".."9"].sample}.join, gdzie n = 8 w Twoim przypadku.

Uogólnione: Array.new(n){[*"A".."Z", *"0".."9"].sample}.join, itd. - from this answer

 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/doraprojects.net/template/agent.layouts/content.php on line 54
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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-17 22:40:34

Oto jeden wiersz prosty kod dla losowego ciągu o długości 8

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

Możesz również użyć go do losowego hasła o długości 8

random_password = ('0'..'z').to_a.shuffle.first(8).join
Mam nadzieję, że to pomoże i będzie niesamowite.
 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/doraprojects.net/template/agent.layouts/content.php on line 54
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/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-13 15:04:26

Oto jeden prosty kod dla losowego hasła z lenth 8

rand_password=('0'..'z').to_a.shuffle.first(8).join
Mam nadzieję, że to pomoże.
 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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-15 06:51:24

Bądź świadomy: rand jest przewidywalny dla atakującego, a zatem prawdopodobnie niepewny. Zdecydowanie powinieneś użyć SecureRandom, jeśli jest to do generowania haseł. Używam czegoś takiego:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-30 14:30:32
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')

Coś z 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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-19 00:25:43

Inna metoda, którą lubię używać

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

Dodaj ljust, jeśli naprawdę masz paranoję co do prawidłowej długości strun:

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-08 23:17:16

Myślę, że to miła równowaga zwięzłości, jasności i łatwości modyfikacji.

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

Łatwo modyfikować

Na przykład, w tym cyfry:

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

Wielkie Litery szesnastkowe:

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

Dla naprawdę imponującej tablicy znaków:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-23 20:34:38

Dodaję tu moje grosze...

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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-16 02:22:00

Możesz użyć String#random z aspektów rubinowego klejnotu facets:

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

W zasadzie robi to:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-22 22:53:52

Moim ulubionym jest (:A..:Z).to_a.shuffle[0,8].join. Zauważ, że shuffle wymaga 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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-28 18:18:17

To rozwiązanie wymaga zależności zewnętrznej, ale wydaje się ładniejsze niż inne.

  1. Install 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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-18 16:12:49

Podane:

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

Pojedyncze wyrażenie, może być przekazane jako argument, pozwala na duplikowanie znaków:

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/doraprojects.net/template/agent.layouts/content.php on line 54
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/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-26 18:03:50

Moje 2 grosze:

  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/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-03 15:49:14

Po prostu piszę mały klejnot random_token aby wygenerować losowe tokeny dla większości przypadków użycia, 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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-03 04:01:18

Dzięki tej metodzie możesz przejść w długości abitralnej. Jest ustawiony jako domyślny jako 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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 00:53:41

Jak na razie najbardziej podoba mi się odpowiedź Radara. Podkręciłbym trochę tak:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 02:35:00

Ostatnio robiłem coś takiego, aby wygenerować losowy ciąg 8 bajtów z 62 znaków. Znaki były 0-9, a-z,A-Z. miałem tablicę z nich, jak było zapętlanie 8 razy i wybierając losową wartość z tablicy. To było wewnątrz aplikacji rails.

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

Najdziwniejsze jest to, że mam sporo duplikatów. Teraz przypadkowo to nie powinno się zdarzyć. 62^8 jest ogromny, ale z 1200 lub tak kodów w db miałem sporą liczbę duplikatów. Zauważyłem one dzieją się na granicach godzin od siebie. Innymi słowy, mogę zobaczyć duple o 12: 12:23 i 2:12: 22 lub coś w tym stylu...Nie wiem, czy czas jest problemem, czy nie.

Ten kod był przed utworzeniem obiektu activerecord. Przed utworzeniem rekordu kod ten uruchamiał się i generował kod 'unikalny'. Wpisy w db zawsze były tworzone rzetelnie, ale kod (str w powyższej linii) był powielany zbyt często.

I created a script to run through 100000 iteracji tej powyżej linii z niewielkim opóźnieniem, więc zajęłoby to 3-4 godziny w nadziei, że zobaczę jakiś wzór powtarzania na godzinę, ale nic nie widziałem. Nie mam pojęcia, dlaczego tak się dzieje w mojej aplikacji 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/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-07 20:16:09