V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
stone000
V2EX  ›  程序员

[求助] 怎么随机产生不重复的 18 位序列类似 MD5

  •  
  •   stone000 · 2020-12-18 08:15:43 +08:00 · 5393 次点击
    这是一个创建于 1438 天前的主题,其中的信息可能已经有所发展或是发生改变。
    怎么随机产生不重复的 18 位序列类似 MD5 这种,或者随机生成 17 位+1 位校验位
    如果产生重复的就通过校验位来处理
    36 条回复    2020-12-18 21:58:01 +08:00
    opengps
        1
    opengps  
       2020-12-18 08:17:53 +08:00
    18 位重复的概率已经够低了,需要强制不重复,那就考虑下中间某几位加入毫秒级时间因素
    CEBBCAT
        2
    CEBBCAT  
       2020-12-18 08:27:07 +08:00 via Android
    递增…
    loading
        3
    loading  
       2020-12-18 08:30:55 +08:00 via Android
    unix 时间戳改成 36 进制(字母+数字)然后再拼接一点随机
    liuzhaowei55
        4
    liuzhaowei55  
       2020-12-18 08:36:07 +08:00 via Android
    产生速度?不快的话就存起来
    netnr
        5
    netnr  
       2020-12-18 08:38:11 +08:00 via Android
    c# 可以生成 GUID 再转 long 长度好像是 19 位,再截取处理一下
    40EaE5uJO3Xt1VVa
        6
    40EaE5uJO3Xt1VVa  
       2020-12-18 08:40:12 +08:00   ❤️ 2
    时间戳已经不可重复了,用 md5 加密时间戳字符串。

    字符串 1608251975
    16 位 小写 b555936fee3a6904
    16 位 大写 B555936FEE3A6904
    32 位 小写 db59d207b555936fee3a6904d80629b4
    32 位 大写 DB59D207B555936FEE3A6904D80629B4
    stone000
        7
    stone000  
    OP
       2020-12-18 08:50:21 +08:00
    比如輸入 A 物品,得到一個唯一 18 位序列號 A18,下次再輸入 A 物品還是得到 A18
    zachlhb
        8
    zachlhb  
       2020-12-18 08:53:12 +08:00 via Android
    按一些规律编码再截取不就行了
    bnlt
        9
    bnlt  
       2020-12-18 08:54:10 +08:00
    先用自增生成 0001 0002 这样的序列,然后用可逆对称加密算法对其加密,每次都会得到一个看似随机,而且不会重复的值。

    类似功能我很早之前写过一个,用来在 PostgreSQL 里面实现类似题主的需求,数据库已经没了,代码有一份放在 runjs 上,今天想去看看,结果网站也已经关了……

    当时用的加密算法的名字忘了,但实现很简单,大概 10 行代码左右,秘钥长度和明文长度一样,照着维基百科上面对那个算法的说明写出来的,大致过程是循环替换。

    有谁知道是什么加密算法吗,也帮我回忆回忆
    jorneyr
        10
    jorneyr  
       2020-12-18 08:57:15 +08:00
    计算的到 MD5 后,冲突时随机把中间得某 1 位,2 位,3 位的大小写变化一下,直到不冲突
    TomVista
        11
    TomVista  
       2020-12-18 08:57:27 +08:00
    考虑线程安全吗?🐶
    stone000
        12
    stone000  
    OP
       2020-12-18 08:58:29 +08:00
    @TomVista 不考慮
    TomVista
        13
    TomVista  
       2020-12-18 09:15:30 +08:00
    @stone000 时间戳拼接随机字符串 可能是最简单的方法了
    yogogo
        14
    yogogo  
       2020-12-18 09:32:12 +08:00
    我现在一个做法是先 md5(uniqid())获取一个随机串,然后再把随机串打乱获取 18 位。
    rimutuyuan
        15
    rimutuyuan  
       2020-12-18 09:35:04 +08:00
    时间戳 + 时间戳的 md5[:18]

    每次生成前 sleep 1 nano second
    swithinzhang
        16
    swithinzhang  
       2020-12-18 09:44:58 +08:00
    @yogogo #14 这不是画蛇添足吗
    no1xsyzy
        17
    no1xsyzy  
       2020-12-18 10:06:53 +08:00
    产生重复用校验位处理?那还叫校验位吗?

    #7 你 MD5 截前 18 位不就行了(
    描述修改了你还是 append 吧
    lwlizhe
        18
    lwlizhe  
       2020-12-18 10:13:49 +08:00
    抬个杠

    md5 本身也是有冲突概率的;当然那概率小到只要不是特意针对,基本不会发生冲突的情况,所以放心大胆的把 md5 当作一般文件的校验指纹没啥问题;

    但是因此 md5 的方式并不绝对完美,或者应该说有压缩的算法基本都会有冲突吧~~
    ElmerZhang
        19
    ElmerZhang  
       2020-12-18 10:15:36 +08:00
    两处 hash 方式各取一段拼成 18 位
    lwlizhe
        20
    lwlizhe  
       2020-12-18 10:18:44 +08:00
    Jooooooooo
        21
    Jooooooooo  
       2020-12-18 10:30:31 +08:00
    拼一个时间戳

    可以忽略重复的可能
    bnlt
        22
    bnlt  
       2020-12-18 10:34:31 +08:00   ❤️ 1
    CREATE OR REPLACE FUNCTION public.hexid(p integer)
    RETURNS text
    LANGUAGE plcoffee
    AS $function$
    b = 15

    f = (r, k) ->
    ((r * k) + 51735) & ((1 << b) - 1)

    fc = (n, ks) ->
    l = n >> b
    r = n & ((1 << b) - 1)

    for k in ks
    t = l
    l = r
    r = t ^ f(r, k)

    (l << b) + r

    r = fc(p, [24358, 25934, 52897, 8057])

    return ('00000000' + r.toString(16)).slice(-8)
    $function$

    我找回代码了,但还是不知道里面的算法是什么🥺
    入参是 1 2 3 4 这样用数据序列自增产生的,返回值看上去就是随机数,但实际是加密算法算出来,由于加密算法可逆,所以保证了产生的值不会重复。
    vus520
        23
    vus520  
       2020-12-18 10:40:32 +08:00
    难道不可以套用雪花算法吗
    4771314
        24
    4771314  
       2020-12-18 10:45:45 +08:00
    uuid
    touch
        25
    touch  
       2020-12-18 10:51:00 +08:00
    不是应该上雪花 id 算法,保证你不重复
    laminux29
        26
    laminux29  
       2020-12-18 10:52:50 +08:00
    我把 18 位,理解为由 18 个[a-z0-9]组成的字符。因为如果 18 位指的是 2^18,那就啥都别做了。

    18 个由[a-z0-9]组成的字符,那就是 36^18,大约 2^93 次方。

    两种方法:

    第一种方法,限制没毫秒内调用次数,直接借用 Twitter 的开源分布式 ID 生成算法:snowflake 。
    41bit 时间戳;

    12bit 的毫秒内序列号(每毫秒最多调用 4096 次,如果需要更多次数,可以放大这部分的长度);

    以上这两者,在每秒最多 4096 次调用内,保障了全局唯一。那么剩下 40bit 你自己随便找个快速 hash 算法,然后截取前面 40bit 就行了。


    第二种方法,不限制每秒最多调用次数,但限制总长度。

    x Bit,从 1 开始的自增 ID,x 为 2^x 的长度,由自增 + 放号业务来保障全局唯一。

    剩下 93-x,随便找个快速 hash 算法,然后截取最前面的 93-xbit 就行了。
    mxT52CRuqR6o5
        27
    mxT52CRuqR6o5  
       2020-12-18 11:24:28 +08:00
    用对称加密算法加密自增序列,秘钥不泄露就基本等于随机
    bnlt
        28
    bnlt  
       2020-12-18 11:33:32 +08:00
    找到我用的算法的名字了:费斯妥密码
    https://zh.wikipedia.org/wiki/%E8%B4%B9%E6%96%AF%E5%A6%A5%E5%AF%86%E7%A0%81
    这个算法没有限制加密块的长度,所以你可以产生任意位数的结果,算法可逆保证不会重复,不需要补随机数或截取(随机数和截取理论上还是会导致重复),复合一定条件时,超过 4 轮可以实现强伪随机
    lululau
        29
    lululau  
       2020-12-18 11:38:52 +08:00
    雪花算法正解,重不重复要看生成频率
    bnlt
        30
    bnlt  
       2020-12-18 11:55:27 +08:00
    雪花算法和 UUID 主要目的是让 ID 在服务器之间也不重复,但是看上去并没有那么随机,人类能从中找出一些规律知道 ID 之间的关系,比如雪花算法前面部分会暴露出两个 ID 之间的先后顺序关系。当然 UUID 也有 UUID v4 整串都是随机生成的,不会被看出规律
    xiaomimix5
        31
    xiaomimix5  
       2020-12-18 14:15:23 +08:00
    # Nano ID
    A tiny, secure, URL-friendly, unique string ID generator for JavaScript.
    https://github.com/ai/nanoid#readme
    julyclyde
        32
    julyclyde  
       2020-12-18 15:39:56 +08:00
    只要长度有限,最后必然会重复
    br00k
        34
    br00k  
       2020-12-18 18:09:13 +08:00
    把 12byte 的 MongoDB ObjectId 转成 base64,只有 16 位长度。
    siyemiaokube
        35
    siyemiaokube  
       2020-12-18 21:52:24 +08:00 via iPhone
    这 tm 的……这届 v 站水平真菜……

    以后尽可能不和数学不好的人共事……
    Ptu2sha
        36
    Ptu2sha  
       2020-12-18 21:58:01 +08:00
    确实 有几层楼的回复是来搞笑的吗?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3645 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 05:03 · PVG 13:03 · LAX 21:03 · JFK 00:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.