2011-05-06 72 views
5

我需要生成一個唯一的六位數字字母數字代碼。將我的數據庫保存爲憑證號:對於每筆交易。如何在Ruby中生成唯一的六位字母數字代碼

+2

爲什麼你不簡單地自動遞增代碼?然後他們會是數字。如果代碼太多(超過6位數字),則可以使用此編號的Base32編碼,例如 – Jens 2011-05-06 10:49:07

+0

可能重複? http://stackoverflow.com/questions/88311/how-best-to-generate-a-random-string-in-ruby – Teoulas 2011-05-06 10:50:59

+0

@Teoulas我不這麼認爲。在這個問題中沒有任何內容說明代碼需要(或出現)隨機的。 – Phrogz 2011-05-06 17:26:47

回答

3

我用這個

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

How to generate a random string in Ruby這種聯繫是有益的

+1

這是一個很有可能發生碰撞的非常糟糕的答案。在100萬次迭代中,215萬個鍵上有767個**千**碰撞。將隨機數從「10000」變爲「10000000」會將碰撞減少到「僅」,在1,000,000中爲31,000,但任何碰撞仍然不好。無論Time.now是否總是相同,或者每次調用返回一個新值(例如,每秒不超過一個事務),情況都是如此。 – Phrogz 2011-05-06 17:25:18

+0

在正常情況下,這是可以接受的。有沒有其他的方式呢。 – rubyprince 2011-05-11 10:20:09

0

更好的方法是讓數據庫處理ID(遞增)。但是如果你堅持爲自己生成它們,你可以使用一個隨機生成器來生成一個代碼,用db來檢查它的唯一性。然後接受或再生

+0

理論上這是一個壞主意,因爲你開始填充可用的命名空間,因爲碰撞的可能性會增加,並且在極端情況下,最終可能會在找到一個空閒密鑰之前停留在一個很長時間的再生循環中。 – Phrogz 2011-05-06 16:57:12

0

我會用數據庫生成唯一的密鑰,但如果你堅持這樣做硬盤的方式:

class AlnumKey 

    def initialize 
    @chars = ('0' .. '9').to_a + ('a' .. 'z').to_a 
    end 

    def to_int(key) 
    i = 0 
    key.each_char do |ch| 
     i = i * @chars.length + @chars.index(ch) 
    end 
    i 
    end 

    def to_key(i) 
    s = "" 
    while i > 0 
     s += @chars[i % @chars.length] 
     i /= @chars.length 
    end 
    s.reverse 
    end 

    def next_key(last_key) 
    to_key(to_int(last_key) + 1) 
    end 
end 

al = AlnumKey.new 
puts al.next_key("ab") 
puts al.next_key("1") 
puts al.next_key("zz") 

當然,你必須存儲當前的關鍵某個地方,這也是沒有辦法的線程/多區安全等

0

有以下限制:

  1. 有效期至2038年12月24日零點40分35秒UTC
  2. 生成不止一次內的第二

你可以使用這個簡單的代碼:

Time.now.to_i.to_s(36) 
# => "lks3bn" 
+2

如果系統時間改變會發生什麼? – Zabba 2011-05-06 17:10:42

+0

一次我需要獲得不同的代金券ID – 2011-05-06 18:12:48

+0

@Zabba這將導致一個問題,但我認爲它不會那麼頻繁。在這種情況下,系統必須在等於新舊時區之間差異的時間段內停機維護。這將是不到一天,最壞的情況。如果新的時區繼續前進,則系統不必關閉。 – sawa 2011-05-06 22:22:29

0
class IDSequence 
    attr_reader :current 
    def initialize(start=0,digits=6,base=36) 
    @id, @chars, @base = start, digits, base 
    end 
    def next 
    s = (@id+=1).to_s(@base) 
    @current = "0"*(@chars-s.length) << s 
    end 
end 

id = IDSequence.new 
1234.times{ id.next } 

puts id.current 
#=> 0000ya 

puts id.next 
#=> 0000yb 

9876543.times{ id.next } 
puts id.current 
#=> 05vpqq 
0

這eleviat e通過獲得毫秒來解決時間衝突問題

(Time.now.to_f*1000.0).to_i 
相關問題