2011-05-06 74 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 
相关问题