web-dev-qa-db-ja.com

Rubyでランダムな文字列を生成する方法

私は現在、 "A" .. "Z"の8文字の擬似ランダムな大文字の文字列を生成しています。

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
921
Kent Fredric

SecureRandomを使わないのはなぜですか?

require 'securerandom'
random_string = SecureRandom.hex

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

SecureRandomには以下のメソッドもあります。

  • base64
  • random_bytes
  • random_number

参照してください: http://Ruby-doc.org/stdlib-1.9.2/libdoc/securerandom/rdoc/SecureRandom.html

763

保証された最大長を持つランダムなURLにやさしい文字列を生成するためにこれを使用します。

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

小文字のa-zと0-9のランダムな文字列を生成します。あまりカスタマイズできませんが、短くてきれいです。

241

このソリューションは、アクティベーションコード用の読みやすい文字列を生成します。 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
167
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の場合、「=」も使用されます。

125
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を除外します。 Ruby 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解決策はSecureRandomの約3/4の時間しかかかりません。本当にたくさんの文字列を生成するのであれば問題になるかもしれませんが、時々ランダムな文字列を作成するのであれば、もっと安全な実装を使うことをお勧めします。

38
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)

2n0-9を含む長さa-fのランダムな文字列を生成します

24

Array.new(n){[*"0".."9"].sample}.join、ここではn = 8です。

一般化:Array.new(n){[*"A".."Z", *"0".."9"].sample}.joinなど - from this answer

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

これは長さ8のランダムな文字列の1行の単純なコードです。

 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

私が使用したいもう一つの方法

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

あなたが本当に正しい文字列の長さに妄想しているならljustを追加してください:

 Rand(2**256).to_s(36).ljust(8,'a')[0..7]
6
user163365
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')

工夫から何か

6
Thorpe Obazee

ここにセントを追加するだけです。

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

ruby GemのFacets facetsString#randomを使うことができます。

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

私はこれが簡潔さ、明快さ、そして修正のしやすさの素晴らしいバランスであると思います。

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

大文字の16進数

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. Gem faker をインストールしてください
  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

私は最近62文字から8バイトのランダムな文字列を生成するためにこのようなことをしていました。文字は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)が頻繁に複製されていました。

1時間ごとにある種の繰り返しパターンを見ることを期待して3〜4時間かかるように、私は少し遅れて上記の行の10万回の反復を実行するスクリプトを作成しましたが、何も見ませんでした。なぜこれが私のRailsアプリで起こったのか私にはわかりません。

3
erik

あなたがUNIXを使っていて、まだRailsなしでRuby 1.8(SecureRandomではない)を使わなければならないなら、これを使うこともできます:

random_string = `openssl Rand -base64 24`

これは新しいシェルを生み出すことに注意してください。これは非常に遅く、スクリプトにのみ推奨されます。

2
lzap

Ruby 1.8以降で動作し、高速であるもう1つのトリックは以下のとおりです。

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

ランダムな16進数文字列です。同様の方法で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

私のベストショット、3つの範囲からなるランダムな文字列に対する2つの解決策

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

これは別の方法です:

  • Rand()の代わりに安全な乱数ジェネレータを使用します
  • URLやファイル名に使用できます
  • 大文字、小文字、数字を含みます
  • あいまいな文字を含まないオプションがあります。

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つの数字と1つの特殊文字を含むパスワードを保証します。

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

あなたの最初を1つのステートメントにするには:

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

最も簡単な方法はstring_pattern gem 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'は最適ではないと誰かが言っています。私たちが持っていたアイデアの1つは母音を削除することでした、しかしあなたはまだ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' Gem GithubLink を使用してください

これは、Rails 2、Rails 3、Rails 4、Rails 5互換の乱数値を生成する最も簡単な方法を提供します。

0
Rubyist