it-swarm-eu.dev

Jak generovat náhodný řetězec v Ruby

V současné době generuji 8 znakový pseudonáhodný řetězec velkých písmen "A" .. "Z":

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

ale nevypadá čistě a nemůže být předán jako argument, protože to není jediné prohlášení. Chcete-li získat smíšený řetězec "a" .. "z" plus "A" .. "Z", změnil jsem ho na:

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

ale vypadá to jako odpad.

Má někdo lepší metodu?

702
Jeff
(0...8).map { (65 + Rand(26)).chr }.join

Trávím příliš mnoho času golfem.

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

A poslední, která je ještě matoucí, ale flexibilnější a plýtvá méně cykly:

o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten
string = (0...50).map { o[Rand(o.length)] }.join
908
Kent Fredric

Proč nepoužívat SecureRandom?

require 'securerandom'
random_string = SecureRandom.hex

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

SecureRandom má také metody pro:

  • base64
  • random_bytes
  • random_number

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

754
christopherstyles

Používám toto pro generování náhodných URL přátelských řetězců s garantovanou maximální délkou:

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

Generuje náhodné řetězce malých písmen a-z a 0-9. Není to příliš přizpůsobitelné, ale je to krátké a čisté.

236

Toto řešení generuje řetězec snadno čitelných znaků pro aktivační kódy; Nechtěl jsem, aby lidé matou 8 s B, 1 s I, 0 s O, L s 1, atd.

# 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

Jiní se zmínili o něčem podobném, ale to používá funkci bezpečné URL.

require 'securerandom'
p SecureRandom.urlsafe_base64(5) #=> "UtM7aa8"
p SecureRandom.urlsafe_base64 #=> "UZLdOkzop70Ddx-IJR0ABg"
p SecureRandom.urlsafe_base64(nil, true) #=> "i0XQ-7gglIsHGV2_BNPrdQ=="

Výsledek může obsahovat A-Z, a-z, 0-9, “-” a “_”. "=" Se také používá, pokud je výplň pravdivá.

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

Generování náhodného řetězce 8 písmen (např. NVAYXHGR)

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

Generování náhodného 8 znakového řetězce (např. 3PH4SWF2) vylučuje 0/1/I/O. Ruby 1.9

45
Shai Coleman

Vzhledem k tomu, že Ruby 2.5 je velmi snadné s SecureRandom.alphanumeric:

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

Generuje náhodné řetězce obsahující A-Z, a-z a 0-9, a proto by mělo být použitelné ve většině případů použití. A jsou generovány náhodně, což může být také přínosem.


Upravit: měřítko pro porovnání s řešením, které má nejvíce 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)

Řešení Rand trvá tedy pouze asi 3/4 času SecureRandom. Mohlo by se jednat o to, jestli generujete opravdu hodně řetězců, ale pokud si z času na čas vytvoříte nějaký náhodný řetězec, vždycky budu s bezpečnější implementací (protože je také jednodušší volat a explicitněji).

34
Markus

Nemohu si vzpomenout, kde jsem to našel, ale zdá se mi, že je to nejlepší a nejméně intenzivní proces pro mě:

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

Chcete-li řetězec zadané délky, použijte:

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

Bude generovat náhodný řetězec délky 2n obsahující 0-9 a a-f

24

Array.new(n){[*"0".."9"].sample}.join, kde n = 8 ve vašem případě.

Zobecněno: Array.new(n){[*"A".."Z", *"0".."9"].sample}.join, atd. - z toto odpověď

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

Zde je jeden řádek jednoduchý kód pro náhodný řetězec s délkou 8

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

Můžete jej také použít pro náhodné heslo s délkou 8

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

doufám, že to pomůže a úžasné.

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

Buďte si vědomi: Rand je předvídatelný pro útočníka a je tedy pravděpodobně nejistý. Měli byste určitě použít SecureRandom, pokud je to pro generování hesel. Používám něco takového:

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
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')

Něco z Devise

6
Thorpe Obazee

Jen tady přidávám své centy ...

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

můžete použít String#random z Tvaru Ruby Gem facets:

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

v podstatě to dělá:

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

Další metodu, kterou rád používám

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

Přidejte ljust, pokud jste opravdu paranoidní o správné délce řetězce:

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

Myslím, že je to pěkná rovnováha stručnosti, jasnosti a snadnosti modifikace. 

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

Snadno upravitelný

Například, včetně číslic:

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

Hexadecimální velká písmena:

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

Pro skutečně působivé pole znaků:

characters = (32..126).to_a.pack('U*').chars.to_a
5
Nathan Long

Moje oblíbená je (:A..:Z).to_a.shuffle[0,8].join. Všimněte si, že shuffle vyžaduje Ruby> 1.9.

4
Josh

Toto řešení vyžaduje vnější závislost, ale zdá se být hezčí než jiné.

  1. Nainstalovat klenot podvodník
  2. Faker::Lorem.characters(10) # => "ang9cbhoa8"
4
asiniy

Vzhledem k:

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

Jeden výraz může být předán jako argument, umožňuje duplicitní znaky:

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

Moje 2 centy:

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

Jen jsem napsal malý drahokam random_token generovat náhodné tokeny pro většinu případů použití, užívejte si ~

https://github.com/sibevin/random_token

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

Dělal jsem něco takového nedávno, abych vygeneroval 8 bajtový náhodný řetězec ze 62 znaků. Znaky byly 0-9, a-z, A-Z. Měl jsem řadu z nich, jak se opakoval 8 krát a vybírat náhodné hodnoty z pole. To bylo uvnitř aplikace Rails.

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

Podivná věc je, že jsem měl dobrý počet duplikátů. Teď by se to mělo náhodou stát. 62 ^ 8 je obrovský, ale z 1200 nebo tak kódů v db jsem měl dobrý počet duplikátů. Všiml jsem si, že se dějí na hranicích hodin. Jinými slovy, mohu vidět duple v 12:12:23 a 2:12:22 nebo něco takového ... nevíte, zda je čas problémem nebo ne.

Tento kód byl před vytvořením objektu activerecord. Před vytvořením záznamu by tento kód spustil a vygeneroval „jedinečný“ kód. Záznamy v db byly vždy vyráběny spolehlivě, ale kód (str. Ve výše uvedeném řádku) byl duplikován příliš často.

Vytvořil jsem skript pro běh přes 100000 iterací tohoto výše uvedeného řádku s malým zpožděním, takže by to trvalo 3-4 hodiny doufat, že uvidím nějaký druh opakování na hodinovém základě, ale nic neviděl. Nemám ponětí, proč se to stalo v mé aplikaci Rails.

3
erik

Pokud jste na systému UNIX a stále musíte používat Ruby 1.8 (bez SecureRandom) bez Rails, můžete také použít toto:

random_string = `openssl Rand -base64 24`

Všimněte si, že tento spouští nový Shell, to je velmi pomalé a může být doporučeno pouze pro skripty.

2
lzap

Další trik, který pracuje s Ruby 1.8+ a je rychlý je:

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

Dostaneš náhodný hex řetězec. Podobně byste měli být schopni generovat řetězec base64 ('M *').

2
lzap

Mám rád radarovou odpověď nejlépe, myslím. Takhle bych to trochu vylepšil:

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

Pomocí této metody můžete procházet libovolnou délkou. Je nastavena jako výchozí hodnota 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

Můj nejlepší záběr, 2 řešení pro náhodný řetězec skládající se ze 3 rozsahů

(('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

zkuste to

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

Mám rád odpovědi na vlákno, byly velmi užitečné, opravdu !, ale pokud mohu říci, žádný z nich nesplňuje mé oči, možná je metoda Rand (). je to pro mě prostě nezdá, protože máme na výběr metodu volby Array #.

2

Zde je další metoda:

  • Namísto Rand používá zabezpečený generátor náhodných čísel ()
  • Lze použít v adresách URL a názvech souborů
  • Obsahuje velká písmena, malá písmena a čísla
  • Má možnost nezahrnout dvojznačné znaky I0l01

Potřebuje 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

To je založeno na několika dalších odpovědích, ale přidává trochu složitější:

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

V podstatě zajišťuje heslo o délce 8 - 20 znaků, které obsahuje alespoň jedno číslo a jeden speciální znak.

1
Chris Bloom

Pro devise secure_validatable můžete toto použít

(0 ... 8) .map {([65, 97] .příklad + Rand (26)). Chr} .Push (Rand (99)).

1
shiva kumar

Zde je zlepšení odpovědi @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

Na @Travis R odpověď znaky a čísla byly spolu, takže někdy random_string mohl vrátit pouze čísla nebo jen znaky. S tímto zlepšením bude alespoň polovina random_string znaků a zbytek čísla. Jen v případě, že potřebujete náhodný řetězec s čísly a znaky

0
Lucas Andrade

Chcete-li, aby byl váš první v jednom prohlášení:

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

Nejjednodušší způsob je použít řetězec string_pattern gem https://github.com/MarioRuiz/string_pattern

Například pro generování 36 náhodných písmen:

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

Také můžete použít regulární výrazy

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

Vytvořit prázdný řetězec nebo předběžnou opravu, pokud vyžadují:

myStr = "OID-"

Tento kód použijte k naplnění řetězce náhodnými čísly:

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

Poznámky:

(Rand * 43) + 47).ceil

Bude generovat náhodná čísla od 48-91 (0,1,2..Y, Z)

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

Používá se k přeskočení speciálních znaků (protože nemám zájem je zahrnout)

while(myStr.length < 12)

Bude generovat celkem 12 znaků dlouhý řetězec včetně prefixu.

Vzorový výstup:

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

nebo

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

Použili jsme to v našem kódu:

class String

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

end

Maximální podporovaná délka je 25 (používáme ji pouze s výchozím nastavením, takže to nebyl problém).

Někdo zmínil, že '' '' z 'je suboptimální, pokud se chcete zcela vyhnout vytváření urážlivých slov. Jedním z nápadů, které jsme měli, bylo odstranění samohlásek, ale stále skončíte s WTFBBQ atd.

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

Zde je řešení, které je flexibilní a umožňuje dups:

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

Příklad:

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

Můžete také povolit, aby se určitý znak zobrazoval častěji:

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

Vysvětlení: Výše ​​uvedená metoda přebírá znaky daného řetězce a generuje dostatečně velké pole. Pak to zamíchá, vezme první n položky, pak se k nim připojí.

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

Použít 'SafeRandom' Gem GithubLink

To bude poskytovat nejjednodušší způsob, jak generovat náhodné hodnoty pro Rails2, Rails 3, Rails 4, Rails 5 kompatibilní. 

0
Rubyist