< 返回版块

子十 发表于 2022-01-14 15:27

Tags:md5,32,进制,32进制,16位

起因

发现简书一类的网站资源ID很短不知道如何实现

如 https://www.jianshu.com/p/4a8939c48cd4

这个 12位的(有没有大佬知道这个算法的,后面的问题就不用看了)

然后就考虑到雪花法但生成结果是:6887650413378670482 近20位数字,就考虑是否有其它处理方式

主要目的是想把雪花算法生成的值变得更短

如 6887650413378670482 转换成更短小的格式 16 或12位数字字符串

自己试了又发现了下面2个问题

问题

  1. 找了几个库 md5 加密都是32位的 有没有可以转成16位方式?
let s = "sdsqdwqdew"

// 16
abc511316658f941

// 32
 4a9bf2d9abc511316658f94134f03c0d
  1. 数字进制转换 标准库默认支持到16进制 更高的进制有没有可以使用的库?
// 10 进制数字
let num = 6887650413378670592; 

// 16 进制
5f95d98f02821000
// 32 进制
5Z5ESHW184400

测试过程用到过的库

uuid = { version = "0.8", features = ["serde", "v4"] }
# md5 = "0.7.0"
rust-crypto = "*"   # md5
blob-uuid = "0.4.0"
rs-snowflake = "0.5.0"

评论区

写评论
作者 子十 2022-01-15 19:38
const ALL_CHARS: &'static str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";

/// 进阶版 10 进制转 11 - 64 进制
///
/// ```
/// let raw_id = 6888076346770202619;
/// assert_eq!(base_10_to_n(raw_id, 36), "1gbyra5idyk8r");
/// ```
fn base_10_to_n(num: u64, radix: u32) -> String {
    if num == 0 {
        return String::from("0");
    }

    let base = base_10_to_n(num / (radix as u64), radix);
    let start = base.strip_prefix("0").unwrap_or(base.as_str());
    let end = match ALL_CHARS.chars().nth((num % (radix as u64)) as usize) {
        Some(data) => String::from(data),
        _ => String::from(""),
    };
    format!("{}{}", start, end)
}

/// 11 - 64 进制解析为 10 进制
///
/// ```
/// let id = "1gbyra5idyk8r";
/// let raw_id = 6888076346770202619;
/// assert_eq!(base_n_to_10(id, 36), 6888076346770202619);
/// ```
fn base_n_to_10(num_str: &str, radix: u32) -> u128 {
    let mut result: u128 = 0;
    for i in 0..num_str.len() {
        result *= radix as u128;
        let target_char = num_str.chars().nth(i).unwrap_or('0');
        let data = ALL_CHARS.chars().position(|i| i == target_char).unwrap_or(0);
        result += data as u128;
    }
    result
}
作者 子十 2022-01-15 11:34

根据上面提供的 python 进制转换方式实现了个 62 进制的转换

/// 依赖包: rs-snowflake = "*"

use std::collections::HashMap;
use snowflake::SnowflakeIdBucket;

fn main() {
    test_snow();
}

/// 输出如下:
/// 21bx7gxh03kqi   6887951964563447803
/// 21bx7gxh03kqi   6887951964563447803
/// 21bx7gxh2venr   6887951964567642107
/// 21bx7gxh2venr   6887951964567642107
/// 21bx7gxh2venr   6887951964567642107
/// 21bx7gxh2venr   6887951964567642107
/// 21bx7gxh5o8l1   6887951964571836411
/// 21bx7gxh5o8l1   6887951964571836411
/// 21bx7gxh5o8l1   6887951964571836411
fn test_snow() {
    for _ in 1..10 {
        let (id, raw_id) = get_snow_id();
        println!("{}   {}", id, raw_id);
    }
}

/// 生成雪花算法ID 结果转为36进制
fn get_snow_id() -> (String, u64) {
    let mut b = SnowflakeIdBucket::new(1, 1);
    let raw_id = b.get_id() as u64;
    (base_n(raw_id as u64, 36), raw_id)
}

/// 10 进制转为 11 - 62 进制 36 进制前是小写
fn base_n(num: u64, n: i32) -> String {
    let num_rep: HashMap<i32, char> = HashMap::from([
        (10, 'a'), (11, 'b'), (12, 'c'), (13, 'd'), (14, 'e'),
        (15, 'f'), (16, 'g'), (17, 'h'), (18, 'i'), (19, 'j'),
        (20, 'k'), (21, 'l'), (22, 'm'), (23, 'n'), (24, 'o'),
        (25, 'p'), (26, 'q'), (27, 'r'), (28, 's'), (29, 't'),
        (30, 'u'), (31, 'v'), (32, 'w'), (33, 'x'), (34, 'y'),
        (35, 'z'),
        (36, 'A'), (37, 'B'), (38, 'C'), (39, 'D'), (40, 'E'),
        (41, 'F'), (42, 'G'), (43, 'H'), (44, 'I'), (45, 'J'),
        (46, 'K'), (47, 'L'), (48, 'M'), (49, 'N'), (50, 'O'),
        (51, 'P'), (52, 'Q'), (53, 'R'), (54, 'S'), (55, 'T'),
        (56, 'U'), (57, 'V'), (58, 'W'), (59, 'X'), (60, 'Y'),
        (61, 'Z')
    ]);

    let mut new_num_string = String::from("");
    let mut current: u64 = num;

    while current != 0 {
        let remainder = (current % (n as u64)) as i32;
        let mut remainder_string: String;

        if remainder > 9 && remainder < 62 {
            remainder_string = format!("{}", num_rep.get(&remainder).unwrap());
        } else {
            remainder_string = format!("{}", remainder);
        }

        new_num_string = format!("{}{}", remainder_string, new_num_string);
        current = current / (n as u64);
    }

    new_num_string
}

#[cfg(test)]
mod tests {
    use super::base_n;

    #[test]
    fn test_base_35() {
        let num = 6887946670030594043;
        assert_eq!(base_n(num, 35), "21bx54naqlu18");
    }

    /// 测试16进制结果是否和标准库一致
    #[test]
    fn test_base_16() {
        let num = 6887946670030594043;
        let stand_val = format!("{:x}", num);
        assert_eq!(base_n(num, 16), stand_val);
    }
}

作者 子十 2022-01-14 15:55

感谢 @nxd 提供: 进制转换算法链接: https://blog.csdn.net/dutsoft/article/details/79076327

1 共 3 条评论, 1 页