Как сгенерировать случайную строку в Ruby
Вопрос
В настоящее время я генерирую 8-символьную псевдослучайную строку верхнего регистра для «A»..«З»:
value = ""; 8.times{value << (65 + rand(25)).chr}
но он не выглядит чистым, и его нельзя передать в качестве аргумента, поскольку это не один оператор.Чтобы получить строку со смешанным регистром "a" .."з" плюс "А".."Z", я изменил его на:
value = ""; 8.times{value << ((rand(2)==1?65:97) + rand(25)).chr}
но это похоже на мусор.
Есть ли у кого-нибудь лучший метод?
Решение
(0...8).map { (65 + rand(26)).chr }.join
Я провожу слишком много времени за игрой в гольф.
(0...50).map { ('a'..'z').to_a[rand(26)] }.join
И последний, который еще более запутан, но более гибок и требует меньше циклов:
o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten
string = (0...50).map { o[rand(o.length)] }.join
Другие советы
Почему бы не использовать SecureRandom?
require 'securerandom'
random_string = SecureRandom.hex
# outputs: 5b5cd0da3121fc53b4bc84d0c8af2e81 (i.e. 32 chars of 0..9, a..f)
SecureRandom также имеет методы для:
- база64
- случайные_байты
- случайное число
видеть: http://ruby-doc.org/stdlib-1.9.2/libdoc/securerandom/rdoc/SecureRandom.html
Я использую это для генерации случайных строк, удобных для URL-адресов, с гарантированной максимальной длиной:
rand(36**length).to_s(36)
Он генерирует случайные строки строчных букв a-z и 0-9.Он не очень настраиваемый, но короткий и понятный.
Это решение генерирует строку легко читаемых символов для кодов активации;Я не хотел, чтобы люди путали 8 с B, 1 с I, 0 с O, L с 1 и т. д.
# 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
Другие упоминали нечто подобное, но здесь используется функция безопасного URL-адреса.
require 'securerandom'
p SecureRandom.urlsafe_base64(5) #=> "UtM7aa8"
p SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
p SecureRandom.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="
Результат может содержать A-Z, a-z, 0-9, «-» и «_».«=» также используется, если заполнение истинно.
[*('A'..'Z')].sample(8).join
Создайте случайную строку из 8 букв (например,НВАЙXHGR)
([*('A'..'Z'),*('0'..'9')]-%w(0 1 I O)).sample(8).join
Создайте случайную строку из 8 символов (например,3PH4SWF2), исключает 0/1/I/O.Рубин 1.9
Поскольку с Ruby 2.5 действительно легко SecureRandom.alphanumeric
:
len = 8
SecureRandom.alphanumeric(len)
=> "larHSsgL"
Генерирует случайные строки, содержащие A-Z, a-z и 0-9, поэтому их следует применять в большинстве случаев использования.И они генерируются случайным образом и безопасно, что тоже может быть преимуществом.
Редактировать:Тест для сравнения с решением, получившим наибольшее количество голосов:
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)
Итак rand
решение занимает всего около 3/4 времени SecureRandom
.Это может иметь значение, если вы генерируете действительно много строк, но если вы просто время от времени создаете какую-то случайную строку, я бы всегда выбрал более безопасную реализацию (поскольку ее также проще вызывать и она более явна).
Я не могу вспомнить, где я это нашел, но мне кажется, что это лучший и наименее трудоемкий вариант:
def random_string(length=10)
chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
password = ''
length.times { password << chars[rand(chars.size)] }
password
end
require 'securerandom'
SecureRandom.urlsafe_base64(9)
Если вам нужна строка указанной длины, используйте:
require 'securerandom'
randomstring = SecureRandom.hex(n)
Он сгенерирует случайную строку длины 2n
содержащий 0-9
и a-f
Array.new(n){[*"0".."9"].sample}.join
, где n = 8 в вашем случае.
Обобщенный: Array.new(n){[*"A".."Z", *"0".."9"].sample}.join
, и т. д.- от этот отвечать
require 'sha1'
srand
seed = "--#{rand(10000)}--#{Time.now}--"
Digest::SHA1.hexdigest(seed)[0,8]
Вот простой однострочный код для случайной строки длиной 8
random_string = ('0'..'z').to_a.shuffle.first(8).join
Вы также можете использовать его для случайного пароля длиной 8.
random_password = ('0'..'z').to_a.shuffle.first(8).join
Я надеюсь, что это поможет и удивительно.
Руби 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"
Вот один простой код для случайного пароля длиной 8.
rand_password=('0'..'z').to_a.shuffle.first(8).join
Надеюсь, это поможет.
Имейте в виду: rand
предсказуем для злоумышленника и, следовательно, вероятно, небезопасен.Вам обязательно следует использовать SecureRandom, если это необходимо для генерации паролей.Я использую что-то вроде этого:
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
Еще один метод, который я люблю использовать
rand(2**256).to_s(36)[0..7]
Добавьте lтолько, если вы действительно параноики по поводу правильной длины строки:
rand(2**256).to_s(36).ljust(8,'a')[0..7]
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
Что-то из Девайса
Я думаю, что это хороший баланс краткости, ясности и простоты модификации.
characters = ('a'..'z').to_a + ('A'..'Z').to_a
# Prior to 1.9, use .choice, not .sample
(0..8).map{characters.sample}.join
Легко модифицируется
Например, включая цифры:
characters = ('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a
Заглавные шестнадцатеричные числа:
characters = ('A'..'F').to_a + (0..9).to_a
Для действительно впечатляющего набора персонажей:
characters = (32..126).to_a.pack('U*').chars.to_a
Просто добавляю сюда свои центы...
def random_string(length = 8)
rand(32**length).to_s(32)
end
вы можете использовать String#random
из граней рубинового камня facets
:
в основном он делает это:
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
Мой любимый (:A..:Z).to_a.shuffle[0,8].join
.Обратите внимание, что для перемешивания требуется Ruby > 1.9.
Это решение требует внешней зависимости, но кажется красивее другого.
- Установить драгоценный камень мошенник
Faker::Lorem.characters(10) # => "ang9cbhoa8"
Данный:
chars = [*('a'..'z'),*('0'..'9')].flatten
Одно выражение, которое можно передать в качестве аргумента, допускает дублирование символов:
Array.new(len) { chars.sample }.join
Недавно я делал что-то подобное, чтобы сгенерировать 8-байтовую случайную строку из 62 символов.Символы были 0-9,a-z,A-Z.У меня был их массив, который выполнялся 8 раз и выбирал случайное значение из массива.Это было внутри приложения Rails.
str = ''
8.times {|i| str << ARRAY_OF_POSSIBLE_VALUES[rand(SIZE_OF_ARRAY_OF_POSSIBLE_VALUES)] }
Странно то, что у меня много дубликатов.Теперь случайно это практически никогда не должно происходить.62^8 — это огромно, но из примерно 1200 кодов в базе данных у меня было большое количество дубликатов.Я заметил, что они происходят с разницей в несколько часов.Другими словами, я мог бы увидеть дубль в 12:12:23 и 2:12:22 или что-то в этом роде... не уверен, проблема во времени или нет.
Этот код использовался до создания объекта activerecord.Прежде чем запись была создана, этот код запускался и генерировал «уникальный» код.Записи в базе данных всегда создавались надежно, но код (str в строке выше) дублировался слишком часто.
Я создал сценарий для выполнения 100 000 итераций этой строки с небольшой задержкой, поэтому это заняло 3-4 часа, надеясь увидеть какой-то повторяющийся шаблон ежечасно, но ничего не увидел.Я понятия не имею, почему это происходило в моем приложении Rails.
''.tap {|v| 4.times { v << ('a'..'z').to_a.sample} }
Мои 2 цента:
def token(length=16)
chars = [*('A'..'Z'), *('a'..'z'), *(0..9)]
(0..length).map {chars.sample}.join
end
Я просто пишу маленькую жемчужину random_token
чтобы генерировать случайные токены для большинства случаев использования, наслаждайтесь ~
С помощью этого метода вы можете передать произвольную длину.По умолчанию установлено значение 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
Я думаю, мне больше всего нравится ответ Радара.Я бы немного подправил так:
CHARS = ('a'..'z').to_a + ('A'..'Z').to_a
def rand_string(length=8)
s=''
length.times{ s << CHARS[rand(CHARS.length)] }
s
end