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

生成唯一字母 ID 求解

  •  
  •   lg106 · 2020-01-22 10:51:13 +08:00 · 10495 次点击
    这是一个创建于 1772 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有一个需求是不用数字作为用户 ID,要用英文字母

    我现在有三种解决方案

    第一种:用户注册时候,生成一个随机英文字符串,去查用户表,如果重复再重新生成,直到唯一。

    第二种:先生成一张字母 ID 表,每次用户从里面取,取了就标记为已用。

    第三种:用函数把用户数字 ID 转为字母 ID,但是转出来的 ID,两个相近的用户,字母 ID 太相似了。

    有什么更好的解决方案吗?

    53 条回复    2020-01-24 22:45:24 +08:00
    Varobjs
        1
    Varobjs  
       2020-01-22 10:57:12 +08:00 via Android
    就是随机生成不唯一的用户名呗
    lg106
        2
    lg106  
    OP
       2020-01-22 10:59:46 +08:00
    @Varobjs 也可以这么说,用户 ID 要显示在外面,我们不想让别人看到我们的数字 ID,所以想用英文来代替,包括我们的文章 ID 也是要弄成英文 ID
    imlinhanchao
        3
    imlinhanchao  
       2020-01-22 11:00:48 +08:00
    @lg106 uuid 可否?
    whypool
        4
    whypool  
       2020-01-22 11:01:07 +08:00
    新增数据可以用 UUID,把横杠去掉就行,就是有点长
    用户名+时间戳+MD5 也能生成唯一 ID
    crypto 库也能生成唯一 ID
    jfcherng
        5
    jfcherng  
       2020-01-22 11:01:56 +08:00 via Android
    hashids
    jinhan13789991
        6
    jinhan13789991  
       2020-01-22 11:03:25 +08:00 via Android
    第一个人是 AAAAAAAA,第二个人是 AAAAAAAB,以此类推~ 变相的 26 进制自增
    eojessie
        7
    eojessie  
       2020-01-22 11:04:46 +08:00
    @jinhan13789991 这个容易被枚举了。。。。
    lg106
        8
    lg106  
    OP
       2020-01-22 11:05:35 +08:00
    @imlinhanchao 可能太长了
    otakustay
        9
    otakustay  
       2020-01-22 11:05:55 +08:00
    就用自增键然后 hash 一下呢
    lg106
        10
    lg106  
    OP
       2020-01-22 11:06:25 +08:00
    @jinhan13789991 我第三种就是这种,可以用函数转化,但容易被找规律
    lg106
        11
    lg106  
    OP
       2020-01-22 11:06:45 +08:00
    @whypool 我试试第三种,UUID 有点长
    lg106
        12
    lg106  
    OP
       2020-01-22 11:06:58 +08:00
    @jfcherng 我试试去
    Varobjs
        13
    Varobjs  
       2020-01-22 11:08:21 +08:00 via Android
    @lg106 那就数字 id md5 下就可以了,多方便
    lg106
        14
    lg106  
    OP
       2020-01-22 11:10:25 +08:00
    @Varobjs 我忘了说了,长度只能是 8 到 10 位,太长了不行,类似这种 rczlihkgyt
    GM
        15
    GM  
       2020-01-22 11:10:45 +08:00   ❤️ 1
    HashID 了解一下,数据表可以继续用自增 id 字段,对外做个转换变成 HashID 就好了。
    009694
        16
    009694  
       2020-01-22 11:14:45 +08:00 via iPhone
    前两种方案有什么缺点吗?
    Marmot
        17
    Marmot  
       2020-01-22 11:17:01 +08:00   ❤️ 2
    hashids 靠谱
    cgpiao
        18
    cgpiao  
       2020-01-22 11:17:40 +08:00 via iPhone
    设备 id + 自定义格式时间 + 自增 转换为 36 进制
    lg106
        19
    lg106  
    OP
       2020-01-22 11:22:37 +08:00
    试了下 hashids,这个完美解决,感谢大佬们
    eason1874
        20
    eason1874  
       2020-01-22 11:25:52 +08:00
    怕 ID 暴露可以用 36 进制,36 个字符打乱顺序就不好猜了,但如果获得连续 ID 还是可以破解出来。
    vanishcode
        21
    vanishcode  
       2020-01-22 11:33:42 +08:00
    https://github.com/souyunku/SnowFlake
    不知道是不是楼主想要的。。
    xaplux
        22
    xaplux  
       2020-01-22 11:37:31 +08:00
    @vanishcode 很明显不是,楼主想要的是全字母的,17 楼说的 hashids 靠谱
    tabris17
        23
    tabris17  
       2020-01-22 11:50:06 +08:00
    snowflake 算法生成 64 位整数

    然后转换成 base53 字符串(仅包含字母和下划线)
    hubqin
        24
    hubqin  
       2020-01-22 11:52:24 +08:00
    取巧,JavaScript:Math.random().toString(36).slice(2)
    wengcd
        25
    wengcd  
       2020-01-22 11:55:45 +08:00
    https://hashids.org

    配置密钥,真实🆔根据密钥生成 hash 值;有密钥可反推出真实🆔,没有则无法反推
    alaikis
        26
    alaikis  
       2020-01-22 11:58:50 +08:00
    数字 36 进制
    MrYELiex
        27
    MrYELiex  
       2020-01-22 13:00:43 +08:00
    snowflake
    Raymon111111
        28
    Raymon111111  
       2020-01-22 13:10:39 +08:00
    snowflake 这种方案然后把 0 到 9 映射到 a - j 上就行了.

    一个简单的实现是, 当前时间(unixtime, 秒和毫秒都可以) + 机器码(比如集群是 100 个机器, 那就号码就是 00 - 99) + 三位轮询的数(每个机器启动时候就拿到一个打乱的大小是 1000 的数组, 里面的数是 000 - 999, 生成的时候从里面取数然后移除, 空了再生成一次)

    这么干冲突的概率相当小(几乎不会有)
    ZSeptember
        29
    ZSeptember  
       2020-01-22 14:37:27 +08:00
    uuid->hash->baese64 取前 10 位
    sleepm
        30
    sleepm  
       2020-01-22 14:43:25 +08:00
    有个自增主键 id,然后,先插入新纪录,然后获取 id,再根据 id 生成全字母的 ID
    luopengfei14
        31
    luopengfei14  
       2020-01-22 14:44:56 +08:00 via iPhone
    36、62 进制都可以
    fx
        32
    fx  
       2020-01-22 15:33:21 +08:00
    hashids
    jeremaihloo
        33
    jeremaihloo  
       2020-01-22 16:14:54 +08:00
    nanoid

    github.com 上搜一下,不同语言都有实现,一定程度上满足需求吧
    qsbaq
        34
    qsbaq  
       2020-01-22 16:29:22 +08:00
    把 ID 弄个 md5 肯定唯一了
    songco
        35
    songco  
       2020-01-22 16:44:02 +08:00
    没有可读性要求可以直接 id 映射一下就行, 比如数字转换成 16 进制; 比如 0-9 映射成 10 个字幕

    有可读性要求的话, 准备字典, 然后随机生成两到组拼起来, 预先生成也行; 生成后查重复也行; 直接按顺序映射也可以, 生成的结果大概类似 docker 的默认名字, 比如 adoring_lovelace 之类的
    Liang
        36
    Liang  
       2020-01-22 16:45:08 +08:00
    @qsbaq md5 在一定概率下会重复的
    wzwwzw
        37
    wzwwzw  
       2020-01-22 18:50:25 +08:00
    uuid 去掉 - 呗。
    kkkkkrua
        38
    kkkkkrua  
       2020-01-22 19:18:38 +08:00 via iPhone
    将数字转成 58 进制
    hauzi
        39
    hauzi  
       2020-01-22 20:11:54 +08:00 via iPhone
    第一种
    fireapp
        40
    fireapp  
       2020-01-22 20:13:47 +08:00 via iPhone
    mongo object id 还不错可以试试
    lasuar
        41
    lasuar  
       2020-01-22 20:18:44 +08:00
    利用自增思想,A->B 等效于 1->2
    fdingiit
        42
    fdingiit  
       2020-01-22 20:22:46 +08:00
    有请求,再创建不是一个好的生产环境策略。

    我们的生产环境上,id 是有个预资源池,初始可能是 n 位,随用随取。如果用完了,就 stop the world 并再生成一个位数为 n+1 的 id 新池子。

    这个思路的来源是编译器中内存分配以及垃圾回收的几个简单算法。
    gamexg
        43
    gamexg  
       2020-01-22 21:02:00 +08:00
    hashid 挺好,
    我做过类似的另一个需求,
    不过原始 id 是二进制数据,直接固定 iv 的 aes 流加密来做的。
    rogwan
        44
    rogwan  
       2020-01-22 21:07:26 +08:00
    hashids + 盐。
    LancerEvo
        45
    LancerEvo  
       2020-01-22 21:28:07 +08:00
    记得在某个公司的代码里见过一个微服务 用的第二种实现
    zyqhi
        46
    zyqhi  
       2020-01-22 21:43:43 +08:00 via iPhone
    26 进制
    ech0x
        47
    ech0x  
       2020-01-22 21:53:22 +08:00
    生成一个 UUID 不就行了,UUID3 或者 UUID5
    wd
        48
    wd  
       2020-01-22 22:17:07 +08:00 via iPhone
    我觉得第一种就挺好的 uuid 里面取几位用 不会那么大概率需要生成第二次
    zpvip
        49
    zpvip  
       2020-01-22 22:42:41 +08:00 via Android
    我不知道为什么 Ruby on Rails 在国内这么不受待见。这个需求一行代码就搞定了

    gem 'friendly_id'
    lookas2001
        50
    lookas2001  
       2020-01-23 00:34:20 +08:00 via Android
    8 位 id 取 5 次都有重复的可能性基本上就为 0 了
    所以,第一种
    dandandanerdan
        51
    dandandanerdan  
       2020-01-23 06:57:56 +08:00
    uuid 是最安全的
    polymerdg
        52
    polymerdg  
       2020-01-23 09:05:53 +08:00
    我用的是 MD5(用戶名+時間戳+隨機 6 位)
    huzb
        53
    huzb  
       2020-01-24 22:45:24 +08:00
    用函数把用户 ID 转成字母 ID 是最好的,可以确保唯一且在前端就完成校验。相近 ID 这个可以用混淆和扩散的方式把变化打乱。我有总结过一篇文章:huzb.me/2018/03/23/简单的密码学生成唯一邀请码 /
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3138 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 13:55 · PVG 21:55 · LAX 05:55 · JFK 08:55
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.