วิธีสร้างสตริงแบบสุ่มใน Ruby


746

ขณะนี้ฉันกำลังสร้างสตริงตัวพิมพ์ใหญ่หลอกแบบ 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}

แต่ดูเหมือนว่าถังขยะ

ใครบ้างมีวิธีที่ดีกว่า


ฉันไม่เข้าใจว่าทำไมคุณถึงสนใจ "เพราะมันไม่ใช่คำเดียวมันไม่สามารถผ่านเป็นข้อโต้แย้ง" ทำไมไม่เพียงแค่ทำให้มันเป็นประโยชน์หรือวิธีการช่วยเหลือ?
David J.

1
สมมติว่ามีวิธีการรีเซ็ตรหัสผ่านของผู้ใช้และมีอาร์กิวเมนต์สำหรับรหัสผ่านใหม่ ฉันต้องการที่จะผ่านสตริงแบบสุ่มในรหัสข้างต้นฉันต้องการตัวแปร tmp ในขณะที่ในตัวอย่างคำสั่งเดียวร้องฉันสามารถทำสิ่งทั้งหมดเป็นหนึ่งซับ แน่ใจว่าวิธีการอรรถประโยชน์อาจจะดีในระยะยาวโดยเฉพาะอย่างยิ่งถ้าฉันต้องการที่คล้ายกันที่นี่และที่นั่น แต่บางครั้งคุณก็ต้องการมันในสถานที่หนึ่งครั้งเสร็จแล้ว
Jeff

ไม่คุณไม่ต้องใช้ตัวแปรชั่วคราว ลองสิ่งนี้: reset_user_password!(random_string)ที่ไหนdef random_string; SecureRandom.urlsafe_base64(20) end
David J.

8 ตัวอักษรเป็นรหัสผ่านที่อ่อนแออย่างน่าอับอาย ได้รับ md5sum ที่เครื่องคอมพิวเตอร์ที่ทันสมัยสามารถกู้คืนรหัสผ่านใน30 วินาที แล้วจะมีอะไรอีกต่อไปsecurerandom.urlsafe_base64
พันเอก Panic

1
ทำไมสิ่งนี้จึงมีคำตอบมากมาย ไม่ใช่ว่ามันไม่ใช่คำถามที่มีประโยชน์ แต่ฉันอยากรู้ว่ามันดึงดูดความสนใจได้อย่างไร
Lou

คำตอบ:


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

205
34 ('a'..'z').to_a.shuffle[0,8].joinตัวอักษรและที่เห็นได้ชัดอย่างรวดเร็ว: หมายเหตุ: คุณจะต้องทับทิม> = shuffle1.9
fny

20
การใช้ประโยชน์จากห้องสมุดที่มีอยู่จะดีกว่าถ้าคุณไม่มีโปรแกรมควบคุมที่จะม้วนของคุณเอง ดูSecureRandomเป็นตัวอย่างหนึ่งในคำตอบอื่น ๆ
David J.

28
@faraz วิธีการของคุณไม่สามารถใช้งานได้เหมือนกัน แต่ไม่ใช่การสุ่มเปลี่ยน
michaeltwofish

35
[*('a'..'z'),*('0'..'9')].shuffle[0,8].joinเพื่อสร้างสตริงแบบสุ่มที่มีทั้งตัวอักษรและตัวเลข
Robin

31
randสามารถกำหนดได้และคาดการณ์ได้ อย่าใช้สิ่งนี้เพื่อสร้างรหัสผ่าน! ใช้SecureRandomวิธีแก้ไขปัญหาอย่างใดอย่างหนึ่งแทน
ดินสอ

800

ทำไมไม่ใช้ 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


11
base64 ต้องการ แต่ไม่ใช่ hex เหมือนในตัวอย่างของเขา
Jeff Dickey

67
โดยวิธีการมันเป็นส่วนหนึ่งของ stdlib ใน 1.9 และ 1.8 รุ่นล่าสุดดังนั้นหนึ่งสามารถที่require 'securerandom'จะได้รับSecureRandomผู้ช่วยที่เป็นระเบียบนี้:)
J -_- L

21
BTW SecureRandom ถูกลบออกจาก ActiveSupport ในเวอร์ชัน 3.2 จากการเปลี่ยนแปลง: "ลบ ActiveSupport :: SecureRandom เพื่อสนับสนุน SecureRandom จากไลบรารีมาตรฐาน"
Marc

15
SecureRandom.random_number(36**12).to_s(36).rjust(12, "0")จะสร้างสตริงที่มี 0-9a-z (36 ตัวอักษร) ที่มีความยาว 12 ตัวเสมอ เปลี่ยน 12 เป็นความยาวเท่าใดก็ได้ที่คุณต้องการ Integer#to_sแต่น่าเสียดายที่ไม่มีทางที่เพิ่งได้รับอาริโซน่าใช้
เจอร์รี่ชอว์

1
@ stringo0 ที่ผิด หากคุณต้องการที่จะ+fGH1ผ่าน URL คุณเพียงแค่ต้องเข้ารหัส URL เหมือนที่คุณต้องการค่าใด ๆ ที่จะผ่าน URL: %2BfGH1
nzifnab

247

ฉันใช้สิ่งนี้เพื่อสร้างสตริงที่เป็นมิตรกับ URL แบบสุ่มด้วยความยาวสูงสุดที่รับประกัน

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

มันสร้างสตริงสุ่มของตัวพิมพ์เล็ก az และ 0-9 มันไม่ได้ปรับแต่งได้มาก แต่มันสั้นและสะอาด


4
+1 สำหรับรุ่นที่สั้นที่สุด (ที่ไม่ได้เรียกไบนารีภายนอก ^^) ถ้าสตริงแบบสุ่มไม่ได้หันสาธารณะบางครั้งผมแม้เพียงแค่ใช้rand.to_s; น่าเกลียด แต่ใช้งานได้
Jo Liss

12
นี่คือทางออกที่ดี (และรวดเร็วเกินไป) แต่บางครั้งจะผลิตสตริงภายใต้ lengthความยาวประมาณหนึ่งครั้งใน ~ 40
ไบรอัน E

7
@ Brian E (36**(length-1) + rand(36**length)).to_s(36)นี่จะรับประกันตัวเลขที่คุณต้องการ: 36 ** (ยาว -1) แปลงเป็นฐาน 36 คือ 10 ** (ยาว -1) ซึ่งเป็นค่าที่เล็กที่สุดที่มีความยาวหลักที่คุณต้องการ
Eric Hu

11
นี่คือรุ่นที่ผลิตสัญญาณโทเค็นตามความยาวที่ต้องการเสมอ:(36**(length-1) + rand(36**length - 36**(length-1))).to_s(36)
Adrien Jarthon

3
สิ่งนี้ทำให้ฉันมีข้อผิดพลาดใน Rails 4 และ Ruby 2.1.1: NameError: undefined local variable or method length สำหรับ main: Object`
kakubei

175

โซลูชันนี้สร้างสตริงของอักขระที่อ่านได้ง่ายสำหรับรหัสเปิดใช้งาน ฉันไม่ต้องการให้ผู้คนสับสน 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

3
'U' คลุมเครือหรือว่าเป็นตัวพิมพ์ผิด
gtd

10
@gtd - ใช่แล้ว U และ V คือ ambigvovs
โคลินม์

1
@colinm V อยู่ที่นั่นแม้ว่า
gtd

8
เพื่อความปลอดภัยคุณต้องใช้SecureRandom.random_number(charset.size)แทนrand(charset.size)
gtd

1
ฉันแค่พยายามปรับปรุงเรื่องนี้โดยการเพิ่มตัวพิมพ์เล็กและ / หรืออักขระพิเศษบางตัว (Shift + num) และได้รายการต่อไปนี้: %w{ A C D E F G H J K L M N P Q R T W X Y Z 2 3 4 6 7 9 ! @ # $ % ^ & * +}และ%w{ A D E F G H J L N Q R T Y a d e f h n r y 2 3 4 7 ! @ # $ % ^ & * }(รายการแรกไม่รวมตัวพิมพ์เล็ก แต่ยาวกว่า) ค่อนข้างน่าสนใจ ทำงานออกมา
dkniffin

130

คนอื่น ๆ พูดถึงสิ่งที่คล้ายกัน แต่ใช้ฟังก์ชัน URL ที่ปลอดภัย

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

ผลลัพธ์อาจมี AZ, az, 0-9,“ -” และ“ _” “ =” ยังใช้หากการเติมเต็มเป็นจริง


นี่คือสิ่งที่ฉันกำลังมองหา ขอบคุณ!
Dan Williams

69

ตั้งแต่ Ruby 2.5 เป็นเรื่องง่ายด้วยSecureRandom.alphanumeric:

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

มันสร้างสตริงสุ่มที่มี AZ, az และ 0-9 และดังนั้นจึงควรใช้ในกรณีการใช้งานส่วนใหญ่ และพวกมันก็สร้างความปลอดภัยแบบสุ่มซึ่งอาจเป็นประโยชน์เช่นกัน


นี่เป็นมาตรฐานในการเปรียบเทียบกับโซลูชันที่มี 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)

ดังนั้นrandวิธีการแก้ปัญหาใช้เวลาเพียงประมาณ 3/4 SecureRandomของเวลาของ นั่นอาจสำคัญถ้าคุณสร้างสตริงจำนวนมาก แต่ถ้าคุณเพียงแค่สร้างสตริงสุ่มบางครั้งผมก็จะมีการใช้งานที่ปลอดภัยมากขึ้นเพราะมันจะง่ายต่อการโทรและชัดเจนมากขึ้น


48
[*('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


4
ปัญหาเดียวคือตัวละครแต่ละตัวในผลลัพธ์ที่ไม่ซ้ำกัน จำกัด ค่าที่เป็นไปได้
tybro0103

1
หากคำขอคุณลักษณะนี้ผ่านไปได้ Ruby 1.9.x อาจลงท้ายด้วย #sample สำหรับการสุ่มตัวอย่างโดยไม่มีการแทนที่และ #choice สำหรับการสุ่มตัวอย่างที่มีการแทนที่
David J.

นี่เป็นข้อผิดพลาดฉันคิดว่าคุณต้องการ ... [*("A".."Z")]'; ((ไม่ใช่ qoutes เดียว))
jayunit100

คุณบอกฉันได้ไหมว่าฉันจะทำstubสิ่งนี้rspecให้สำเร็จได้อย่างไร
Sinscary

31

ฉันจำไม่ได้ว่าพบที่ไหน แต่ดูเหมือนว่าดีที่สุดและใช้กระบวนการน้อยที่สุด:

def random_string(length=10)
  chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789'
  password = ''
  length.times { password << chars[rand(chars.size)] }
  password
end

7
บางทีคุณอาจพบมันที่นี่? travisonrails.com/2007/06/07/generate-random-text-with-ruby
ถึงแก่กรรม

ไม่มี 0 และ 1 ที่หายไปจากสิ่งนี้ใช่ไหม
sunnyrjuneja

ดูเหมือนว่าอาจเป็นที่ฉันพบมัน
Travis Reeder

และยาดูเหมือนว่า 0 และ 1 จะหายไป
Travis Reeder

4
0และ1และOและIถูกจงใจหายไปเพราะตัวอักษรเหล่านั้นไม่ชัดเจน หากมีการใช้รหัสประเภทนี้เพื่อสร้างชุดอักขระที่ผู้ใช้ต้องการคัดลอกเป็นการดีที่สุดที่จะแยกอักขระที่อาจแยกความแตกต่างออกจากบริบทได้ยาก
แอนดรู

28
require 'securerandom'
SecureRandom.urlsafe_base64(9)

SecureRandom เป็น lib ที่ยอดเยี่ยม ฉันไม่รู้ว่าอยู่ที่นั่น ขอบคุณ
Dogweather

ทางเลือกเก่า skool (และ uglier) ทางเลือก:Random.new.bytes(9)
tardate

4
btw, urlsafe_base64 ส่งคืนสตริงประมาณ 4/3 ความยาวที่ระบุ เพื่อให้ได้สายอักขระที่ยาวอย่างn=9 ; SecureRandom.urlsafe_base64(n)[0..n-1]
แน่วแน่

25

หากคุณต้องการสตริงที่มีความยาวที่ระบุให้ใช้:

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

มันจะสร้างสตริง2nที่มีความยาวแบบสุ่ม0-9และa-f


มันไม่ได้สร้างสตริงของความยาวnก็จริงสร้างสตริงที่ 4/3 nของ
Omar Ali

@OmarAli คุณผิด ตามเอกสารทับทิมในกรณีที่.hexเป็น 2n เอกสารประกอบ: SecureRandom.hex สร้างสตริงเลขฐานสิบหกแบบสุ่ม อาร์กิวเมนต์nระบุความยาวเป็นไบต์ของตัวเลขสุ่มที่จะสร้าง ความยาวของสตริงเลขฐานสิบหกส่งผลให้เป็นสองเท่าของn
Rihards


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

น่าสนใจ แต่ราคาแพงกว่านิดหน่อย
Jeff

ยังไม่มีความสามารถในการ จำกัด ขอบเขตของอักขระ
Kent Fredric

3
โปรดทราบว่าการแยกย่อยฐานสิบหกส่งกลับเฉพาะอักขระ 0-9 และ af
webmat

11

นี่คือโค้ดง่าย ๆ หนึ่งบรรทัดสำหรับสตริงสุ่มที่มีความยาว 8:

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

คุณสามารถใช้รหัสผ่านแบบสุ่มที่มีความยาว 8:

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

2
คุณไม่ควรใช้สิ่งนี้เพื่อสร้างรหัสผ่านของคุณเองเนื่องจากวิธีนี้จะไม่ทำซ้ำตัวอักษร ดังนั้นคุณจะใช้P(36, 8) / 36^8 = 0.4พื้นที่อักขระที่เป็นไปได้สำหรับ 8 ตัวอักษร (~ 2x ง่ายต่อการดุร้าย) หรือP(36, 25) / 36^25 = 0.00001พื้นที่อักขระที่เป็นไปได้สำหรับ 25 อักขระ (~ 100,000 เท่าเพื่อบังคับเดรัจฉานได้ง่ายขึ้น)
Glacials

10

ทับทิม 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"

1
mapวิธีการแก้ปัญหาเป็นสิ่งที่ดีจริงๆ!
Misha Moroshko

คุณสามารถถาม#sampleถึงองค์ประกอบที่คุณต้องการ เช่นALPHABET.sample(10).join... ruby-doc.org/core-2.4.0/Array.html#method-i-sample
odlp

มันผิดจริง sample(10)ให้ 10 ตัวอย่างที่ไม่เหมือนใคร แต่คุณต้องการอนุญาตให้ทำซ้ำ แต่ฉันจะใช้Array.new(10).mapสำหรับการแสดง
SašaZejnilović

ฉันต้องการตัวอักษรและตัวเลขที่มีทั้งตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ ฉันได้เปลี่ยนไปใช้Array.newและไวยากรณ์บล็อกของมัน Array.new(20) { [*'0'..'9', *'a'..'z', *'A'..'Z'].sample }.join
taylorthurlow

8

ระวัง: 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

นี่อาจเป็นทางออกที่ปลอดภัยที่สุด SecureRandom พยายามใช้ API ความปลอดภัยพื้นฐานที่จัดทำโดยระบบปฏิบัติการ หากคุณมี OpenSSL ระบบจะใช้สิ่งนั้นหากคุณใช้ Windows จะเป็นตัวเลือกที่ดีที่สุด ฉันชอบโซลูชันนี้เป็นพิเศษเพราะช่วยให้คุณระบุชุดอักขระสำหรับใช้งาน แม้ว่ามันจะไม่ทำงานหากชุดตัวละครของคุณยาวกว่าค่าสูงสุดของไบต์: 255 ฉันขอแนะนำให้ดูซอร์สโค้ดสำหรับ SecureRandom ในเอกสาร: ruby-doc.org/stdlib-1.9.3/libdoc/securerandom/ rdoc / …
Breedly

8

นี่คือหนึ่งรหัสง่าย ๆ สำหรับรหัสผ่านแบบสุ่มที่มีความยาว 8:

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

7

วิธีอื่นที่ฉันชอบใช้:

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

เพิ่มljustถ้าคุณหวาดระแวงจริงๆเกี่ยวกับความยาวสตริงที่ถูกต้อง:

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

ยิ่งกว่านั้นการคว้าส่วนสำคัญน้อยที่สุดของตัวเลขสุ่มโดยใช้ทางด้านขวามือของสตริง: แรนด์ (2 ** 64) .to_s (36) [- 10,10]
Jeff

6
SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')

บางสิ่งบางอย่างจากประดิษฐ์


ทำไมมันแทนที่ตัวอักษรสตริงใช้.tr('+/=lIO0', 'pqrsxyz')?
miguelcobain

อักขระพิเศษเนื่องจากไม่ปลอดภัยสำหรับ URL และ l / I หรือ O / 0 เพราะสับสนง่ายมากถ้าคุณใช้เทคนิคเพื่อสร้างรหัสผ่านผู้ใช้ที่อ่านได้
ToniTornado

ฟังก์ชันนั้นมีอคติเล็กน้อยต่อตัวละครบางตัว สำหรับความยาวอื่น ๆ (เช่น 16) อักขระตัวสุดท้ายจะไม่ถูกสุ่ม นี่คือวิธีหลีกเลี่ยงสิ่งนั้น SecureRandom.base64 (64) .tr ('+ / = lIO01', '') [0,16]
Shai Coleman

5

ฉันคิดว่านี่เป็นความสมดุลที่ดีของความกระชับความคมชัดและความง่ายในการปรับเปลี่ยน

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

1
ฉันอยากจะแนะนำสิ่งนี้ให้ใช้ตัวอักษรพิมพ์ใหญ่ + ตัวเลขให้ลบตัวอักษร charset = (1..9) .to_a.concat (('A' .. 'Z'). to_a) .reject {| a | [0, 1, 'O', 'I']. include? (a)} (0 ... ขนาด). map {charset [rand (charset.size)]} .join
luster

5

เพียงแค่เพิ่มเซ็นต์ของฉันที่นี่ ...

def random_string(length = 8)
  rand(32**length).to_s(32)
end

3
NB: มันจะไม่ส่งคืนสตริงที่แน่นอน + ยาว + ยาว - มันอาจจะสั้นกว่า ขึ้นอยู่กับจำนวนที่ส่งคืนโดยrand
tardate

5

คุณสามารถใช้จากแง่มุมของทับทิมอัญมณีString#randomfacets

มันทำอย่างนี้โดยทั่วไป:

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


4

โซลูชันนี้ต้องการการพึ่งพาจากภายนอก แต่ดูเหมือนดีกว่าที่อื่น

  1. ติดตั้ง Gem faker
  2. Faker::Lorem.characters(10) # => "ang9cbhoa8"

4

ได้รับ:

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

นิพจน์เดียวสามารถส่งผ่านเป็นอาร์กิวเมนต์อนุญาตให้ใช้อักขระซ้ำกัน:

Array.new(len) { chars.sample }.join

3

ฉันชอบคำตอบของ Radar ที่ดีที่สุดเท่าที่ฉันคิด ฉันปรับแต่งเล็กน้อยเช่นนี้:

CHARS = ('a'..'z').to_a + ('A'..'Z').to_a
def rand_string(length=8)
  s=''
  length.times{ s << CHARS[rand(CHARS.length)] }
  s
end

ทำไมไม่ใช้(CHARS*length).sample(length).join?
niels

@niels ข้อเสนอแนะนี้จะสร้างสตริงถ่วงน้ำหนักในความโปรดปรานของตัวละครที่ไม่ซ้ำ ตัวอย่างเช่นหากCHARS=['a','b']วิธีการของคุณจะสร้าง"aa"หรือ"bb"เพียง 33% ของเวลา แต่"ab"หรือ"ba"67% ของเวลา อาจจะไม่ใช่ปัญหา แต่มันก็คุ้มค่าที่จะนึกถึง!
Tom Lord

จุดดี @ TomLord ฉันคิดว่าฉันไม่ได้ตระหนักว่าจริง ๆ แล้วเมื่อฉันโพสต์ข้อเสนอแนะนั้น (แม้ว่าฉันต้องยอมรับว่าฉันจำไม่ได้ว่าโพสต์นั้นเลย: D)
niels




3

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)*""

หนึ่งตัวละครจากแต่ละช่วง

และถ้าคุณต้องการอย่างน้อยหนึ่งตัวละครจากแต่ละช่วงเช่นการสร้างรหัสผ่านแบบสุ่มที่มีตัวพิมพ์ใหญ่หนึ่งตัวอักษรตัวพิมพ์เล็กหนึ่งตัวและตัวเลขหนึ่งตัวคุณสามารถทำสิ่งนี้ได้:

( ('a'..'z').to_a.sample(8) + ('A'..'Z').to_a.sample(8) + (0..9).to_a.sample(8) ).shuffle.join 
#=> "Kc5zOGtM0H796QgPp8u2Sxo1"

และถ้าคุณต้องการบังคับใช้จำนวนหนึ่งของแต่ละช่วงคุณสามารถทำสิ่งนี้:( ('a'..'z').to_a.sample(8) + ('A'..'Z').to_a.sample(8) + (0..9).to_a.sample(8) + [ "%", "!", "*" ].sample(8) ).shuffle.join #=> "Kc5zOGtM0*H796QgPp%!8u2Sxo1"
Joshua Pinter

3

ฉันกำลังทำอะไรแบบนี้เมื่อเร็ว ๆ นี้เพื่อสร้างสตริงสุ่ม 8 ไบต์จาก 62 ตัวอักษร ตัวละครคือ 0-9, az, AZ ฉันมีชุดของพวกเขาเป็นวนซ้ำ 8 ครั้งและเลือกค่าสุ่มออกจากอาร์เรย์ นี่เป็นแอพใน Rails

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

สิ่งที่แปลกคือฉันได้รับจำนวนซ้ำมาก ตอนนี้การสุ่มนี่น่าจะไม่เกิดขึ้น 62 ^ 8 มีขนาดใหญ่มาก แต่จาก 1200 หรือมากกว่านั้นรหัสใน db ฉันมีจำนวนซ้ำที่ดี ฉันสังเกตเห็นพวกเขาเกิดขึ้นในขอบเขตชั่วโมงของกันและกัน กล่าวอีกนัยหนึ่งฉันอาจเห็นการตีสองหน้าเวลา 12:12:23 และ 2:12:22 หรืออะไรทำนองนั้น ... ไม่แน่ใจว่าเวลาเป็นปัญหาหรือไม่

รหัสนี้อยู่ในก่อนสร้างวัตถุ ActiveRecord ก่อนที่จะสร้างเรกคอร์ดรหัสนี้จะเรียกใช้และสร้างรหัส 'เฉพาะ' รายการในฐานข้อมูลนั้นสร้างขึ้นอย่างน่าเชื่อถือเสมอ แต่รหัส ( strในบรรทัดด้านบน) ถูกทำซ้ำบ่อยเกินไป

ฉันสร้างสคริปต์เพื่อทำงานซ้ำ 100,000 บรรทัดของบรรทัดด้านบนนี้ด้วยความล่าช้าเล็กน้อยดังนั้นจะใช้เวลา 3-4 ชั่วโมงโดยหวังว่าจะเห็นรูปแบบการทำซ้ำบางอย่างทุกชั่วโมง แต่ไม่เห็นอะไรเลย ฉันไม่รู้ว่าทำไมสิ่งนี้จึงเกิดขึ้นในแอพ Rails ของฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.