golang 简单实现的36进制

作者: 勤劳一沙鸥 | 来源:发表于2019-05-20 18:17 被阅读5次

    概述

    36进制:使用 [0-9,a-z] 描述,逢36进一,即称之为36进制

    var num2char = "0123456789abcdefghijklmnopqrstuvwxyz"
    

    典型应用:汽车号码牌,比如: 京 B0540Z;顺序生成序号等

    进制转换规则参考16进制与10进制转换,大体如下:

    1. 10进制转36进制,用10进制数除了36,取余数得最低1位,然后把商继续除36,得第二位,直到商为0。举例:
    • 126110
    • 1261 除 36 余数 35 (对应 Z),商 1
    • 1 除 36 余数 1 (对应1),商 0 结束
    • 得到 (Z1)36
    1. 36进制转10进制,36进制数按权展开,从右边第一个数开始,每一个乘以16的n次方,n从0开始,每次递增1,然后得出来的每个数相加即是十进制数。举例:
    • (Z1)36 = 35 * 361+ 1 * 360 = 126110
    • (ABC)36 = 10 * 362 + 11 * 361+ 12 * 360 = 1336810

    golang 程序实现:

    编码:

    // 10进制数转换   n 表示进制, 16 or 36
    func NumToBHex(num, n int) string {
        num_str := ""
        for num != 0 {
            yu := num % n
            num_str = string(num2char[yu]) + num_str
            num = num / n
        }
        return strings.ToUpper(num_str)
    }
    

    解码

    // 36进制数转换   n 表示进制, 16 or 36
    func BHex2Num(str string, n int) int {
        str = strings.ToLower(str)
        v := 0.0
        length := len(str)
        for i := 0; i < length; i++ {
            s := string(str[i])
            index := strings.Index(num2char, s)
            v += float64(index) * math.Pow(float64(n), float64(length-1-i)) // 倒序
        }
        return int(v)
    }
    

    测试

    func TestBHex2Num(t *testing.T) {
        assert.Equal(t, BHex2Num("1E6K", 36), 65036)
        assert.Equal(t, BHex2Num("FE0C", 16), 65036)
    
        assert.Equal(t, NumToBHex(65036, 36), "1E6K")
        assert.Equal(t, NumToBHex(65036, 16), "FE0C")
    }
    

    应用: 生成序号

    日期+[A-Z][0-Z]顺序生产,例如 20190520-A0 20190520-A1 ... 20190520-ZZ

    // 按 yymmdd-[A-z][0-Z] 形式生成序号
    func UssNoGenerate(last string) string {
        prefix := time.Now().Format(DateTimeDate)
        value := 0
        if last != "" {
            suffix := strings.Split(last, "-")[1]
            value = BHex2Num(suffix, 36) + 1
        } else {
            value = BHex2Num("A0", 36)
        }
        return prefix + "-" + NumToBHex(value, 36)
    }
    

    应用测试:

    func TestUssNoGenerate(t *testing.T) {
        last := UssNoGenerate("")
        for i := 0; i < 40; i++ {
            fmt.Println(last)
            last = UssNoGenerate(last)
        }
    
    }
    
    // 输出
    20190520-A0
    20190520-A1
    20190520-A2
    20190520-A3
    ...
    20190520-AZ
    20190520-B0
    20190520-B1
    20190520-B2
    20190520-B3
    

    最开始的需求即是生成这些编号,使用字符串截取运算等方式,可以完成,但代码不忍直视,所以改进为些版本。至少原理上非常容易理解。

    你看出bug来了吗,欢迎留言

    相关文章

      网友评论

        本文标题:golang 简单实现的36进制

        本文链接:https://www.haomeiwen.com/subject/mqvqixtx.html