it-swarm.com.ru

Как создать случайную строку в Ruby

В настоящее время я генерирую 8-символьную псевдослучайную строку в верхнем регистре для "A" .. "Z":

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

но он не выглядит чистым и не может быть передан в качестве аргумента, поскольку это не одно утверждение. Чтобы получить строку со смешанным регистром "a" .. "z" плюс "A" .. "Z", я изменил ее на:

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

но это похоже на мусор.

У кого-нибудь есть лучший метод?

710
Jeff
(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
908
Kent Fredric

Почему бы не использовать SecureRandom?

require 'securerandom'
random_string = SecureRandom.hex

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

SecureRandom также имеет методы для:

  • base64
  • random_bytes
  • случайный номер

см .: http://Ruby-doc.org/stdlib-1.9.2/libdoc/securerandom/rdoc/SecureRandom.html

754
christopherstyles

Я использую это для генерации случайных URL-дружественных строк с гарантированной максимальной длиной:

Rand(36**length).to_s(36)

Он генерирует случайные строки из строчных букв a-z и 0-9. Это не очень настраиваемый, но он короткий и чистый.

236
Christoffer Möller

Это решение генерирует строку легко читаемых символов для кодов активации; Я не хотел, чтобы люди путали 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
165
ImNotQuiteJack

Другие упоминали что-то подобное, но для этого используется функция безопасного 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, «-» и «_». «=» Также используется, если отступ равен true.

124
Travis Reeder
[*('A'..'Z')].sample(8).join

Генерация случайной 8-буквенной строки (например, NVAYXHGR)

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

Генерация случайной 8-символьной строки (например, 3PH4SWF2), исключая 0/1/I/O. Рубин 1.9

45
Shai Coleman

С 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. Может иметь значение, если вы генерируете действительно много строк, но если вы просто время от времени создаете какую-то случайную строку, я всегда выбираю более безопасную реализацию (так как ее также проще вызывать и более явной).

34
Markus

Я не могу вспомнить, где я нашел это, но мне кажется, что это лучший и наименее интенсивный процесс:

def random_string(length=10)
  chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
  password = ''
  length.times { password << chars[Rand(chars.size)] }
  password
end
30
Travis Reeder
require 'securerandom'
SecureRandom.urlsafe_base64(9)
27
LENZCOM

Если вы хотите строку указанной длины, используйте:

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

Он сгенерирует случайную строку длиной 2n, содержащую 0-9 и a-f

24
Srikanta Mahapatro

Array.new(n){[*"0".."9"].sample}.join, где n = 8 в вашем случае.

Обобщено: Array.new(n){[*"A".."Z", *"0".."9"].sample}.join и т.д. - из это ответ

13
gr8scott06
require 'sha1'
srand
seed = "--#{Rand(10000)}--#{Time.now}--"
Digest::SHA1.hexdigest(seed)[0,8]
11
Coren

Вот один строчный код для случайной строки длиной 8

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

Вы также можете использовать его для случайного пароля длиной 8

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

я надеюсь, что это поможет и удивительно.

10
Awais

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
Ragmaanir

Помните: 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
8
pencil

Вот один простой код для случайного пароля длиной 8

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

Надеюсь, это поможет.

8
Thaha kp
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')

Что-то от Devise

6
Thorpe Obazee

Просто добавив мои центы здесь ...

def random_string(length = 8)
  Rand(32**length).to_s(32)
end
5
pduersteler

вы можете использовать String#random из Facets of Ruby Gem facets:

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

это в основном делает это:

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
Tilo

Еще один метод, который мне нравится использовать

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

Добавьте ljust, если вы действительно параноик по поводу правильной длины строки:

 Rand(2**256).to_s(36).ljust(8,'a')[0..7]
5
user163365

Я думаю, что это хороший баланс краткости, ясности и простоты модификации. 

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
5
Nathan Long

Мой любимый (:A..:Z).to_a.shuffle[0,8].join. Обратите внимание, что для перемешивания требуется Ruby> 1,9.

4
Josh

Это решение нуждается во внешней зависимости, но кажется более привлекательным, чем другое.

  1. Установить гем фейкер
  2. Faker::Lorem.characters(10) # => "ang9cbhoa8"
4
asiniy

Дано:

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

Одно выражение, которое может быть передано в качестве аргумента, допускает дублирование символов:

Array.new(len) { chars.sample }.join
4
Tim James

Мои 2 цента:

  def token(length=16)
    chars = [*('A'..'Z'), *('a'..'z'), *(0..9)]
    (0..length).map {chars.sample}.join
  end
3
tybro0103

Я просто пишу небольшой гем random_token для генерации случайных токенов для большинства случаев использования, наслаждайтесь ~

https://github.com/sibevin/random_token

3
Sibevin Wang
''.tap {|v| 4.times { v << ('a'..'z').to_a.sample} }
3
eric

Недавно я делал что-то подобное, чтобы генерировать 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. Перед созданием записи этот код запускается и генерирует «уникальный» код. Записи в БД всегда создавались надежно, но код (указанный в строке выше) дублировался слишком часто.

Я создал сценарий для выполнения 100000 итераций этой строки с небольшой задержкой, так что потребуется 3-4 часа в надежде увидеть какой-то повторяющийся шаблон на почасовой основе, но ничего не увидел. Я понятия не имею, почему это происходило в моем приложении Rails.

3
erik

Если вы работаете в UNIX и по-прежнему должны использовать Ruby 1.8 (без SecureRandom) без Rails, вы также можете использовать это:

random_string = `openssl Rand -base64 24`

Обратите внимание, это порождает новую оболочку, это очень медленно, и это может быть рекомендовано только для сценариев.

2
lzap

Еще один трюк, который работает с Ruby 1.8+ и работает быстро:

>> require "openssl"
>> OpenSSL::Random.random_bytes(20).unpack('H*').join
=> "2f3ff53dd712ba2303a573d9f9a8c1dbc1942d28"

Это случайная шестнадцатеричная строка. Аналогичным образом вы сможете генерировать строку base64 ('M *').

2
lzap

Мне кажется, мне больше всего нравится ответ Радар. Я бы немного подправил так:

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
webmat

С помощью этого метода вы можете передать произвольную длину. Он установлен по умолчанию как 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
Ryan Bigg

Мой лучший выстрел, 2 решения для случайной строки, состоящей из 3 диапазонов

(('a'..'z').to_a + ('A'..'Z').to_a + (0..9).to_a).sample(8).join

([*(48..57),*(65..90),*(97..122)]).sample(8).collect(&:chr)*""
2
peter

попробуй это

def Rand_name(len=9)
  ary = [('0'..'9').to_a, ('a'..'z').to_a, ('A'..'Z').to_a]
  name = ''

  len.times do
    name << ary.choice.choice
  end
  name
end

Я люблю ответы в этой ветке, они мне очень помогли, но, если можно так выразиться, ни один из них не удовлетворит меня, может быть, это метод Rand (). это просто не кажется мне правильным, так как у нас есть метод выбора Array #.

2
Manuel A. Guilamo

Вот еще один метод:

  • Он использует безопасный генератор случайных чисел вместо Rand ()
  • Может использоваться в URL и именах файлов
  • Содержит прописные, строчные буквы и цифры
  • Имеет возможность не включать неоднозначные символы I0l01

Необходимо require "securerandom"

def secure_random_string(length = 32, non_ambiguous = false)
  characters = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a

  %w{I O l 0 1}.each{ |ambiguous_character| 
    characters.delete ambiguous_character 
  } if non_ambiguous

  (0...length).map{
    characters[ActiveSupport::SecureRandom.random_number(characters.size)]
  }.join
end
2
Evgenii
10.times do 
  alphabet = ('a'..'z').to_a
  string += alpha[Rand(alpha.length)]
end
1
mminski

Это основано на нескольких других ответах, но добавляет немного большей сложности:

def random_password
  specials = ((32..47).to_a + (58..64).to_a + (91..96).to_a + (123..126).to_a).pack('U*').chars.to_a
  numbers  = (0..9).to_a
  alpha    = ('a'..'z').to_a + ('A'..'Z').to_a
  %w{i I l L 1 O o 0}.each{ |ambiguous_character| 
    alpha.delete ambiguous_character 
  }
  characters = (alpha + specials + numbers)
  password = Random.new.Rand(8..18).times.map{characters.sample}
  password << specials.sample unless password.join =~ Regexp.new(Regexp.escape(specials.join))
  password << numbers.sample  unless password.join =~ Regexp.new(Regexp.escape(numbers.join))
  password.shuffle.join
end

По сути, он обеспечивает пароль длиной от 8 до 20 символов, который содержит как минимум одно число и один специальный символ.

1
Chris Bloom

Для разработки secure_validatable вы можете использовать это

(0 ... 8) .map {([65, 97] .sample + Rand (26)). Chr} .Push (Rand (99)). Join

1
shiva kumar

Вот улучшение ответа @Travis R:

 def random_string(length=5)
    chars = 'abdefghjkmnpqrstuvwxyzABDEFGHJKLMNPQRSTUVWXYZ'
    numbers = '0123456789'
    random_s = ''
    (length/2).times { random_s << numbers[Rand(numbers.size)] }
    (length - random_s.length).times { random_s << chars[Rand(chars.size)] }
    random_s.split('').shuffle.join
  end

На @Travis R символы ответа и числа были вместе, поэтому иногда random_string мог возвращать только цифры или только символы. С этим улучшением по крайней мере половина random_string будет символами, а остальные числа. На всякий случай, если вам нужна случайная строка с цифрами и символами

0
Lucas Andrade

Чтобы сделать ваше первое в одном утверждении:

(0...8).collect { |n| value  << (65 + Rand(25)).chr }.join()
0
Kevin Conner

Самый простой способ - использовать гем string_pattern https://github.com/MarioRuiz/string_pattern

Например, чтобы сгенерировать 36 случайных букв:

 require 'string_pattern'
 puts '36:L'.gen

Также вы можете использовать регулярные выражения

 require 'string_pattern'
 puts /[a-zA-Z]{36}/.gen
0
Mario Ruiz

Создайте пустую строку или предварительное исправление, если требуется:

myStr = "OID-"

Используйте этот код для заполнения строки случайными числами:

begin; n = ((Rand * 43) + 47).ceil; myStr << n.chr if !(58..64).include?(n); end while(myStr.length < 12)

Заметки:

(Rand * 43) + 47).ceil

Он будет генерировать случайные числа от 48-91 (0,1,2..Y, Z)

!(58..64).include?(n)

Он используется для пропуска специальных символов (поскольку мне не интересно включать их)

while(myStr.length < 12)

Он будет генерировать всего 12 символов длинной строки, включая префикс.

Пример вывода:

"OID-XZ2J32XM"
0
Ghazi
a='';8.times{a<<[*'a'..'z'].sample};p a

или же

8.times.collect{[*'a'..'z'].sample}.join
0
Michael Kingski

Мы использовали это в нашем коде:

class String

  def self.random(length=10)
    ('a'..'z').sort_by {Rand}[0,length].join
  end

end

Максимальная поддерживаемая длина - 25 (мы все равно используем ее по умолчанию, поэтому проблем не было).

Кто-то упомянул, что «a» .. «z» неоптимально, если вы хотите полностью избежать создания оскорбительных слов. Одной из идей, которые у нас были, было удаление гласных, но вы все равно получили WTFBBQ и т.д.

0
Carlos Villela
`pwgen 8 1`.chomp
0
Nathan L Smith

Вот решение, которое является гибким и позволяет дупс:

class String
  # generate a random string of length n using current string as the source of characters
  def random(n)
    return "" if n <= 0
    (chars * (n / length + 1)).shuffle[0..n-1].join  
  end
end

Пример:

"ATCG".random(8) => "CGTGAAGA"

Вы также можете позволить определенному персонажу появляться чаще:

"AAAAATCG".random(10) => "CTGAAAAAGC"

Объяснение: Приведенный выше метод берет символы данной строки и генерирует достаточно большой массив. Затем он тасует его, берет первые n элементов, а затем присоединяет их.

0
Abdo
Array.new(8).inject(""){|r|r<<('0'..'z').to_a.shuffle[0]}  # 57
(1..8).inject(""){|r|r<<('0'..'z').to_a.shuffle[0]}        # 51
e="";8.times{e<<('0'..'z').to_a.shuffle[0]};e              # 45
(1..8).map{('0'..'z').to_a.shuffle[0]}.join                # 43
(1..8).map{Rand(49..122).chr}.join                         # 34
0
Automatico

Используйте драгоценный камень «SafeRandom» GithubLink

Это обеспечит самый простой способ генерирования случайных значений для Rails2, Rails 3, Rails 4, Rails 5 совместимых. 

0
Rubyist