【问题标题】:Create a unique id with built-in checksum?使用内置校验和创建唯一 ID?
【发布时间】:2012-02-02 19:59:11
【问题描述】:

我想自动生成一个唯一的 8-10 个字符的 ID 字符串,其中包含某种校验和位,以防止数据输入时出现拼写错误。我更喜欢没有序列号的东西,数据输入人员最终会陷入“常规”并习惯于一直输入相同的序列。

是否有与这类事情相关的最佳实践/陷阱?

更新:好的,我想我需要提供更多细节。

  1. 我想使用字母数字,而不仅仅是数字
  2. 我想要类似于信用卡校验和的行为,除了 8-10 个字符而不是 16 位数字
  3. 我希望 id 是唯一的;应该没有碰撞的可能。

第二次更新好的,我不明白这有什么令人困惑的地方,但我会尝试进一步解释。我正在尝试创建将在表格上显示的跟踪号,这些表格将在以后填写并输入数据。我将生成 id 并将其贴在表单上; id 必须是唯一的,它需要支持很多数字,并且需要合理地防止数据输入。

我不知道这是否已经做到了,或者即使可以做到,但问也无妨。

【问题讨论】:

  • 那么,基本上是 ISBN、UPC 还是 EAN?
  • 我对你的问题感到困惑。您说您想自动生成一个 ID 字符串,但您担心数据输入过程中的拼写错误。是用户创建 ID 字符串还是自动创建的?
  • @ArashN GUID 没有校验位。
  • @ArashN - GUID 的长度超过 8-10 个字符。
  • 类似的东西,是的。诀窍是以易于验证的方式自动生成唯一值。

标签: c# unique checksum


【解决方案1】:

您的问题非常笼统 - 因此只是一些一般方面:

  • ID 是否需要“不可猜测”? 如果是,那么应该混合某种哈希值。

  • ID 是否需要“安全”(例如激活密钥或其他东西)? 如果是,那么应该混合使用某种公钥加密技术。

  • ID/校验和计算需要快速吗? 如果是,那么也许一些非常简单的算法,如 CRC32 或 Luhn(信用卡校验和算法)或 soem 条形码校验和算法可能值得一看。

  • ID 生成是否集中? 如果没有,那么您可能需要检查 GUID、当前时间、MAC 地址和类似的东西。

更新 - 根据 cmets:

  • 在数据库中使用序列
  • 获取该值并对其进行哈希处理,例如使用 MD5
  • 取该哈希的最低有效 40-48 位
  • 将其编码为 Base-36(0-9 和 A-Z),从而为您提供 8-10 个“数字”(字母数字)
  • 对照 DB 检查结果,如果 ID 已经存在则丢弃(因为极少可能发生冲突)
  • 计算 CRC-6-ITU(参见第 3 页上的 http://www.itu.int/rec/T-REC-G.704-199810-I/en
  • 将 CRC 结果附加为最后一个“数字”(也是 base-36)
  • 因此您有一个唯一的 ID,包括校验和

要检查输入的值,您只需从除最后一位以外的所有数字重新计算 CRC-6-ITU,并将结果与​​最后一位数字进行比较。

以上内容相当“不可猜测”,但绝对不是“高安全性”。

更新 2 - 根据评论:

有关如何在 javascript 中计算 CRC 的一些灵感,请参阅 this - 它包含 CRC-8 等的 javascript 代码。

您应该能够根据 CRC-6-ITU 多项式调整此代码。

【讨论】:

  • 按照您的问题顺序,不,不,合理,是。
  • GUID 太大,时间太连续,MAC 地址……不知道怎么用,但它是十六进制和 12 个字符。
  • @JeremyHolovacs 感谢您的回答...您会将生成的 ID 存储在数据库中吗?你能在数据库中存储一个额外的值来检查有效性吗?
  • 是的,这些 id 将与与 id 相关的元数据一起存储在数据库中。 (跟踪 id 被分配到什么位置,发送到哪里等)我宁愿不必检查 db 以防止出现拼写错误……这就是为什么我正在寻找一种相对简单的机制来支持客户端验证。不完美,但能够大大减少错误。
  • @JeremyHolovacs 了解,请参阅我的更新以获取分步说明。
【解决方案2】:

您可能会模仿航空公司预订系统:它们将数字转换为 base-36,使用 A-Z 和 0-9 作为字符。因此,它们的上限是 36^6。

如果您需要保证唯一性,并且不希望它们是连续的,则必须将用完的随机数保存在某个表中。

获得随机或伪随机 ID 后,只需计算校验位即可。

Use a CRC algorithm. 它们可以调整为任何所需的长度(在您的情况下为 6 位)。

编辑

如果不清楚:即使您使用字母代码,也必须在生成校验位之前将其转换为数字。

编辑

  1. 校验和验证不是重量级的,可以在客户端用javascript实现。
  2. 六个字符的字母数字(即航空公司记录定位器)= 10 个 octillion 数字。确定就够了吗? (具体结果请参见Wolfram Alpha。)

【讨论】:

  • (我不想创建自己的校验和......我绝对希望已经存在这种做法)
  • +1 表示需要将使用过的 id 保存在表中,如果它们不能连续喷射,则必须是唯一的。
  • bleh... 我希望有一些更优雅的东西。我真的很希望校验和验证能够在客户端运行,而不需要消耗大量的库或集中式资源……但这听起来不太可能。
  • +!这也是一个很好的答案,但对数据库来说有点沉重。
  • 重新编辑上面的 2 - 它不是 6^36(10 octillion)而是 36^6 = 20 亿 1.76 亿 78.2 万 336
【解决方案3】:

大多数信用卡使用Luhn algorithm(也称为 mod10 算法)作为校验和算法来验证卡号。来自维基百科:

Luhn 算法将检测任何一位数的错误,以及 几乎所有相邻数字的换位。然而,它不会, 检测两位数序列 09 到 90 的转置(反之亦然) 反之亦然)。

该算法是通用的,可以应用于任何标识号。

【讨论】:

  • @L.B:请参阅有关问题的 cmets - 您必须将校验和数字添加到生成的 id 中
  • 你的回答只包括那一小部分。
【解决方案4】:

正如@BrokenGlass 所说,您可以使用 Luhn 校验位算法。信用卡等使用 Luhn 算法 modulo 10。Luhn mod 10 计算从仅由十进制数字(0-9 )。但是,它很容易适应为从任何大小的字母表(二进制、八进制、十六进制、字母数字等)中抽取的句子计算校验位

为此,您只需要两个方法和一个属性:

  • 正在使用的字母表中的代码点数。

    这本质上是编号系统的基础。例如,十六进制(以 16 为基数)字母表由 16 个字符组成(忽略区分大小写的问题):'0123456789ABCDEF'。 '0'-'9'有它们通常的含义; 'A'-'F' 是基数为 16 的数字,代表 10-15。

  • 一种将正在使用的字母表中的字符转换为其相应代码点的方法。

    例如在十六进制中,字符“0”-“9”代表代码点 0-9;字符“A”-“F”代表代码点 10-15。

  • 一种将代码点转换为相应字符的方法。

    与上述相反。例如,在十六进制中,代码点 12 将转换为字符“C”。

如果给定的代码点在字母表中不存在,您可能应该通过ArgumentException

维基百科文章"Luhn mod N algorithm"很好地解释了校验位的计算及其验证。

【讨论】:

    猜你喜欢
    • 2011-03-14
    • 1970-01-01
    • 2021-04-03
    • 2022-08-04
    • 1970-01-01
    • 2020-11-23
    • 2017-07-01
    • 1970-01-01
    相关资源
    最近更新 更多