1

我正在生成一个唯一且随机的字母数字字符串段来表示将由用户生成的某些链接。为此,我使用“uuid”数字来确保它的唯一性和随机性,但是,根据我的要求,字符串的长度不应超过 5 个字符。所以我放弃了这个想法。

然后我决定使用 ruby​​ 的随机函数和当前时间戳生成这样一个字符串。我的随机字符串的代码是这样的:-

 temp=DateTime.now
 temp=temp + rand(DateTime.now.to_i)
 temp= hash.abs.to_s(36)   

我所做的是将当前日期时间存储在一个临时变量中,然后生成一个随机数,将当前日期时间作为参数传递。然后在第二行中实际将当前日期时间和随机数加在一起,形成一个唯一且随机的字符串。

很快我发现,当我在两台不同的机器上测试我的应用程序并同时发送请求时,它在 100 多次试验后生成了相同的字符串(虽然很少见)。

现在我在想,在将 to_s(36) 传递给 temp 变量之前,我应该再添加一个参数,例如 mac 地址或客户端 IP 地址。但无法弄清楚如何做到这一点,即使那样它是否会是独一无二的,也不是......

谢谢....

4

3 回答 3

4

ruby 中的SecureRandom使用进程 ID(如果可用)和当前时间。您可以使用 urlsafe_base64(n= 16) 类方法来生成您需要的序列。根据您的要求,我认为这是您最好的选择。

编辑:经过一番测试,我仍然认为这种方法会生成非唯一键。我为条形码生成解决这个问题的方法是:

barcode= barcode_sql_id_hash("#{sql_id}#{keyword}")

在这里,您的关键字可以是时间 + pid。

于 2013-01-28T05:52:20.133 回答
4

如果您确定您永远不需要超过给定 M 数量的唯一值,并且您只需要防止猜测下一个生成的 id 的基本保护,您可以使用线性同余生成器来生成您的标识符。您所要做的就是记住最后生成的 id,并使用以下公式使用它来生成新的:

newid = ( A * oldid + B ) mod M

如果 2³² 不同的 id 值足以满足您的需求,请尝试:

def generate_id
  if @lcg
    @lcg = (1664525 * @lcg + 1013904223) % (2**32)
  else
    @lcg = rand(2**32) # Random seed
  end
end

现在只需选择一组合适的字符来代表 id 少至 6 个字符。大写和小写字母应该可以解决问题,因为 (26+26)^6 > 2^32:

ENCODE_CHARS = [*?a..?z, *?A..?Z]

def encode(n)
  6.times.map { |i|
    n, mod = n.divmod(ENCODE_CHARS.size)
    ENCODE_CHARS[mod]
  }.join
end

例子:

> 10.times { n = generate_id ; puts "%10d = %s" % [n, encode(n)] }

2574974483 = dyhjOg
3636751446 = QxyuDj
 368621501 = bBGvYa
1689949688 = yuTgxe
1457610999 = NqzsRd
3936504298 = MPpusk
 133820481 = PQLpsa
2956135596 = yvXpOh
3269402651 = VFUhFi
 724653758 = knLfVb

由于 LCG 的性质,生成的 id 不会重复,直到所有 2³² 值每个都被使用过一次。

于 2013-01-28T12:53:03.337 回答
2

您无法生成只有五个字符的唯一UUID,对于字符和数字,您的基本空间大约为 56 个字符,因此最多有 56^5 个组合,大约 5.51 亿(大约 2^29)。

如果使用此方案,您将要生成 10.000 个 UUID(UUID 的数量非常少),您将有 1/5.000 的概率生成冲突。使用加密时,足够大空间以避免冲突的标准定义约为 2^80。

从这个角度来看,如果你的算法只生成一个随机整数(一个 32 位 uint 是 2^32,是你提议的大小的 8 倍),你的算法会更好,这显然是一个坏主意。

于 2013-01-28T06:56:58.117 回答