VBA 生成随机唯一的字母数字字符串

Posted

技术标签:

【中文标题】VBA 生成随机唯一的字母数字字符串【英文标题】:VBA generating a random unique alpha-numeric string 【发布时间】:2020-02-12 19:01:44 【问题描述】:

我需要为每条记录创建一个唯一 ID(字符串),因为我正在开发一个允许用户访问唯一 URL 的应用程序,例如:

http://URL.com/BXD31F

以下代码用于创建 URLID:

Public Function getURLID(ID As Double) As String

Randomize
Dim rgch As String
rgch = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"

Dim i As Long
For i = 1 To 5
    getURLID = getURLID & Mid$(rgch, Int(Rnd() * Len(rgch) + 1), 1)
Next

End Function

如何确保创建的 URLID 是唯一的?我需要查询数据库以确保它之前没有生成吗?该表有 500 万条记录。 dlookup 查询会超出我的 MSAccess 数据库的限制。

我考虑过使用时间字符串来生成 URLID:

 Format(Now, "yymmddhhmmss")

但是,我只想要一个简单的 5 个字符的字符串。

【问题讨论】:

Access 可以生成保证每个表唯一的 ID 列。使用它有什么问题? @Tomalak 大概是为了防止 URL 欺骗 (?);即,如果我得到一个url.com/12345 的链接,我可以将 URL 更改为 url.com/12346 以查看我得到的内容,并且根据链接的内容,我不希望这很容易做到。行 ID 的哈希可以工作,但不会更安全。也就是说,OP 的示例 URL 是 http,所以谁知道它需要多么安全。 取决于应用程序的类型。如果内容是公开的,谁在乎是否有人签出相邻的 URL。如果内容不公开,则 URL 参数不应参与身份验证。如果内容是半公开的(无论这意味着什么),您可以使用某种自定义的 base-N 表示法对数字进行编码,以使其不太可预测并且看起来不那么数字,就像链接缩短器那样。 我认为 是 OP 正在寻找的 这能回答你的问题吗? Generate a UNIQUE string made out of numeric / ALPHABET 【参考方案1】:

如何确保创建的 URLID 是唯一的?

你不能。而且不会。研究加密安全的散列算法......甚至那些永远不会“安全”。请注意,散列是 VBA 绝对零内置支持的东西,但 you can leverage .NET for that。

另一种选择是让操作系统生成Globally Unique IDentifiers (GUID); 这些将是独一无二的,...但比几个字符长得多。

祝你好运!

【讨论】:

GUID 应该在所有计算机上“保证唯一”。 (Raymond Chen 有一个很好的帖子:devblogs.microsoft.com/oldnewthing/20080627-00/?p=21823) @Tomalak 对。 48 位是很多计算机......但不是无限的 嗯,是的。从技术上讲,GUID 的数量是有限的,但是一个 GUID 生成两次的机会非常小。它们在所有实际用途中都是独一无二的,几乎不需要担心需要 URL slug 的 Web 应用程序。 所以伙计们,永远不要仅仅为了好玩而生成 GUID。它们对每个人来说都不够 :) @Vityata 每次生成 GUID,一颗恒星在某处变成超新星 =)【参考方案2】:

确保字符串在 VBA 中是唯一的,可以以不同的方式完成。例如,获取每秒唯一的日期时间并给出它:

format(now, "YYMMDDHHNS")

如果它太明显,请考虑稍微改变一下。例如,从日期时间中删除一个随机常量,假设181387(因为它是一个素数)并将其转换为十六进制。然后就可以了:

Function UniqueString() As String

    Const someNumber = 181387 'it is a prime number
    UniqueString = Hex(Format(Now, "YYMMDDHHNS") - someNumber)

End Function

以上内容似乎不适用于 32 位机器。因此,您可以考虑将日期的各个部分拆分为单独的数字并分别对它们进行十六进制处理:

Function UniqueString32() As String

    Const primeNumber = 23        
    Application.Wait Now + #12:00:02 AM#    'waiting 2 seconds
    UniqueString32 = Hex(Format(Now, "YY")) _
                    & Hex(Format(Now, "MM")) _
                    & Hex(Format(Now, "DD")) _
                    & Hex(Format(Now, "HH")) _
                    & Hex(Format(Now, "NS") - primeNumber)

End Function

只要确保在调用函数之前至少有 1 秒,在同一时区调用它。另外,提前考虑夏令时是个好主意。总的来说,这不是一个好主意,会出现很多问题,但对于vba 和ms-access 就可以了。

【讨论】:

使用时间是个好主意(+1)...但是它需要亚毫秒粒度才能可靠,并且应该使用UTC时间,否则DST将使一整套值不-独特。虽然不确定从中删除随机值 - 感觉就像它保证非唯一性。 这是经过测试的吗?给我溢出。 @MathieuGuindon - 一般来说,将唯一字符串放在随机函数的末尾可能是个好主意。例如,BXD31F + UniqueString()。甚至BXD + UniqueString() + 31F,如果产生BXD31F的函数总是返回一个包含6个字符的字符串。 嗯。这可能是罪魁祸首。我是 32 位的。 不,我猜我们正在处理 LongLongLong 或类似的东西......似乎 Hex 在 32 位上出现错误,数字大小为 @987654335 @.【参考方案3】:

我设法解决了我自己的问题。我们需要检查表中是否已经存在 URLID。挑战在于,在查询完全执行之前,不会将 URLID 写入表中。使用可能的 24 个字符中的 6 个将给我们大约 1.91 亿个可能性(24 的 6 次方)。由于我们只需要创建 500 万个 ID,因此重复记录的可能性很小。

我就是这样做的:

第 1 步 - 使用原始代码为 500 万行随机生成一个 URLID

第 2 步 - 使用下面的查询识别重复项并更新为 null

 UPDATE URLIDs SET URLIDs.URL = Null
 WHERE (((URLIDs.URL) In (SELECT [URL] FROM [URLIDs] As Tmp GROUP BY [URL] HAVING 
 Count(*)>1 )));

第 3 步 - 为第 2 步中识别的空值生成新的 URLID。这一次,检查它们是否已存在于表中。见以下代码:

Public Function getURLID(roll As Double) As String
Randomize
Dim rgch As String
rgch = "ABCDEFGHJKLMNPQRSTUVWXYZ"
Dim i As Long

For i = 1 To 6
        getURLID = getURLID & Mid$(rgch, Int(Rnd() * Len(rgch) + 1), 1)
Next

Do Until URLIDExists(getURLID) = False
    getURLID = ""

    For i = 1 To 6
        getURLID = getURLID & Mid$(rgch, Int(Rnd() * Len(rgch) + 1), 1)
    Next
Loop
End Function

下面的函数用来查看URL是否存在

Public Function URLIDExists(URLID As String) As Boolean
Dim RS1
Dim strQuery As String
strQuery = "SELECT * from [URLIDs] where [URL]='" & URLID & "'"
Set RS1 = CurrentDb.OpenRecordset(strQuery)
If RS1.RecordCount > 0 Then
URLIDExists = True
Else
URLIDExists = False
End If
Set RS1 = Nothing
End Function

我重复了第 2 步和第 3 步,直到不再有重复项。每次检查是否存在已确认的 URLID。最终将不再有重复的 URLID。

【讨论】:

以上是关于VBA 生成随机唯一的字母数字字符串的主要内容,如果未能解决你的问题,请参考以下文章

随机生成唯一的四位字符串-由大小写字母和数字组成

在 Access 中生成随机字母数字字符串后检查重复项

excel怎样根据给定的字符生成一个8位的随机字符

生成固定长度的随机字符串[重复]

如何使用PHP生成随机字符串

生成唯一且随机的整数