news 2026/4/25 21:37:51

【A11】身份证号无损压缩到48位的Rust实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【A11】身份证号无损压缩到48位的Rust实现

方案概述

将18位身份证号(含校验码)压缩为48位整数(可存储在u64的低48位),布局如下:

字段位宽说明
addr20 bits行政区划编码(高3位=0表示非大陆,否则为大陆)
date18 bits出生日期相对于2000-03-01的天数偏移(存储时+131072)
seq10 bits顺序码(身份证第15-17位,0~999)

总位宽:20+18+10 = 48 bits。

地址编码规则(20 bits)

非大陆(高3位=0)
  • addr = 1→ 台湾 (710000)
  • addr = 2→ 香港 (810000)
  • addr = 3→ 澳门 (820000)
  • addr = 4→ 海外 (910000)
  • 判断非大陆:(addr >> 17) == 0
大陆地址(高3位≥1)

6位地址码ABCCDD分解为:

  • prov_high:省级第一位(1~6) → 3 bits
  • prov_low:省级第二位(0~6) → 3 bits
  • city:地级代码(01~99) → 7 bits
  • district:县级代码(01~99) → 7 bits

拼装:addr = (prov_high << 17) | (prov_low << 14) | (city << 7) | district

解码时还原:prov_high = (addr >> 17) & 0x7等。

日期编码(18 bits)

  • 基准日期:2000-03-01
  • 偏移量:offset = (birth_date - base_date).days
  • 存储:stored = offset + 131072(保证非负,范围0~262143)
  • 解码:offset = stored - 131072

顺序码(10 bits)

直接取身份证第15-17位的整数(0~999)。

校验码处理

  • 压缩时不存储校验码(由前17位计算得出,属于冗余数据)。
  • 解压时根据前17位重新计算校验码,补全18位。

Rust实现

usechrono::{NaiveDate,Datelike};constBASE_DATE:NaiveDate=NaiveDate::from_ymd_opt(2000,3,1).unwrap();constOFFSET_BIAS:i32=1<<17;// 131072constMASK_ADDR:u64=0xFFFFF;// 20 bitsconstMASK_DATE:u64=0x3FFFF;// 18 bitsconstMASK_SEQ:u64=0x3FF;// 10 bitsconstSHIFT_DATE:u64=10;constSHIFT_ADDR:u64=28;// 校验码权重因子constWEIGHTS:[u8;17]=[7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2];constCHECK_DIGITS:&[u8]=b"10X98765432";/// 计算身份证校验码fnchecksum(id17:&str)->char{letsum:u32=id17.chars().take(17).zip(WEIGHTS.iter()).map(|(ch,w)|ch.to_digit(10).unwrap()*(*wasu32)).sum();letidx=(sum%11)asusize;CHECK_DIGITS[idx]aschar}/// 将6位地址码编码为20位整数fnencode_address(addr6:&str)->u32{matchaddr6{"710000"=>return1,// 台湾"810000"=>return2,// 香港"820000"=>return3,// 澳门"910000"=>return4,// 海外_=>{}}// 大陆地址letchars:Vec<char>=addr6.chars().collect();letprov_high=chars[0].to_digit(10).unwrap()asu32;// 1-6letprov_low=chars[1].to_digit(10).unwrap()asu32;// 0-6letcity=addr6[2..4].parse::<u32>().unwrap();// 01-99letdistrict=addr6[4..6].parse::<u32>().unwrap();// 01-99(prov_high<<17)|(prov_low<<14)|(city<<7)|district}/// 从20位地址码还原6位地址码fndecode_address(addr_code:u32)->String{// 高3位为0 -> 非大陆if(addr_code>>17)==0{returnmatchaddr_code{1=>"710000".to_string(),2=>"810000".to_string(),3=>"820000".to_string(),4=>"910000".to_string(),_=>panic!("Unknown non-mainland type: {}",addr_code),};}// 大陆地址letprov_high=(addr_code>>17)&0x7;letprov_low=(addr_code>>14)&0x7;letcity=(addr_code>>7)&0x7F;letdistrict=addr_code&0x7F;format!("{}{}{:02}{:02}",prov_high,prov_low,city,district)}/// 将出生日期编码为18位整数fnencode_date(birth:NaiveDate)->u32{letdelta=birth.signed_duration_since(BASE_DATE).num_days();(delta+OFFSET_BIASasi64)asu32}/// 从18位整数还原出生日期fndecode_date(stored:u32)->NaiveDate{letdelta=storedasi64-OFFSET_BIASasi64;BASE_DATE+chrono::Duration::days(delta)}/// 编码18位身份证号 -> 48位整数(低48位有效)pubfnencode_id(id18:&str)->u64{letid17=&id18[..17];letaddr6=&id17[0..6];letyear=id17[6..10].parse::<i32>().unwrap();letmonth=id17[10..12].parse::<u32>().unwrap();letday=id17[12..14].parse::<u32>().unwrap();letbirth=NaiveDate::from_ymd_opt(year,month,day).expect("Invalid date");letseq=id17[14..17].parse::<u32>().unwrap();// 0-999letaddr_code=encode_address(addr6)asu64;letdate_code=encode_date(birth)asu64;letseq_code=seqasu64;(addr_code<<SHIFT_ADDR)|(date_code<<SHIFT_DATE)|seq_code}/// 解码48位整数 -> 完整的18位身份证号(含校验码)pubfndecode_id(compressed:u64)->String{letaddr_code=((compressed>>SHIFT_ADDR)&MASK_ADDR)asu32;letdate_code=((compressed>>SHIFT_DATE)&MASK_DATE)asu32;letseq=(compressed&MASK_SEQ)asu32;letaddr6=decode_address(addr_code);letbirth=decode_date(date_code);letseq_str=format!("{:03}",seq);letid17=format!("{}{}{:04}{:02}{:02}{}",addr6,birth.year(),birth.month(),birth.day(),seq_str);letcheck=checksum(&id17);format!("{}{}",id17,check)}#[cfg(test)]modtests{usesuper::*;#[test]fntest_mainland(){letoriginal="11010119900307663X";letcompressed=encode_id(original);letdecoded=decode_id(compressed);assert_eq!(original,decoded);}#[test]fntest_taiwan(){letoriginal="710000198001011234";letcompressed=encode_id(original);letdecoded=decode_id(compressed);assert_eq!(original,decoded);}#[test]fntest_hongkong(){letoriginal="810000199912312345";letcompressed=encode_id(original);letdecoded=decode_id(compressed);assert_eq!(original,decoded);}#[test]fntest_macau(){letoriginal="820000200001015678";letcompressed=encode_id(original);letdecoded=decode_id(compressed);assert_eq!(original,decoded);}#[test]fntest_overseas(){letoriginal="910000199509090987";letcompressed=encode_id(original);letdecoded=decode_id(compressed);assert_eq!(original,decoded);}}### 说明-依赖:需要 chronocrate处理日期。在Cargo.toml 中添加: ~~~[dependencies]chrono="0.4"~~~-判断非大陆:在 decode_address 中通过(addr_code>>17)==0实现,效率高。-错误处理:示例中使用了 unwrap 和 panic,生产环境建议返回Result-完全无损:所有身份证(含港澳台海外)均可精确还原。 ### 使用示例 ```rustfnmain(){letid="11010119900307663X";letcompressed=encode_id(id);println!("压缩后: {:#018x}",compressed);// 0x0000017243f733letrestored=decode_id(compressed);println!("还原: {}",restored);assert_eq!(id,restored);}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/25 21:33:25

HX711数据不稳定问题

根本原因&#xff1a;PC14/PC15 是 STM32F1 的 OSC32 晶振引脚&#xff0c;即使不启用 LSE&#xff0c;这两个引脚也受备份域保护&#xff0c;有以下严重限制&#xff1a; 最大输出频率仅 3MHz&#xff08;无法可靠驱动 SCK&#xff09; 驱动能力极弱&#xff08;最大灌电流仅 …

作者头像 李华
网站建设 2026/4/25 21:29:31

光伏四可装置设备性能评估:光伏组件衰减率与逆变器效率监测

光伏组件与逆变器作为光伏系统能量转换、传输的核心设备&#xff0c;其运行性能直接决定系统发电效率、生命周期收益及安全稳定性。光伏四可装置&#xff08;可观、可测、可控、可调&#xff09;通过构建精准的性能评估体系&#xff0c;实现组件衰减率与逆变器效率的全周期监测…

作者头像 李华
网站建设 2026/4/25 21:26:02

商超装修吊楣装饰铝拉网现场复尺

做工程采购这几年&#xff0c;我见过太多供应商在展厅里把样品吹得天花乱坠&#xff0c;一到项目现场就原形毕露。装饰金属网这行尤其如此——材料属性、表面处理、加工精度、交付周期&#xff0c;任何一环出问题&#xff0c;工地上几十号人都得等你。后来我养成了个习惯&#…

作者头像 李华
网站建设 2026/4/25 21:24:39

【数据结构精讲】线性表四大核心:数组 / Vector、栈、队列、链表(原理 + 模板 + 避坑 + 选型)

一、线性表基础定义线性表是n 个数据元素的有限序列&#xff0c;元素之间满足「一对一」的前驱后继关系&#xff0c;除首尾元素外&#xff0c;每个元素有且仅有一个前驱和一个后继。本文聚焦线性表的四大核心实现&#xff1a;数组 / Vector、栈、队列、链表&#xff0c;从底层原…

作者头像 李华
网站建设 2026/4/25 21:19:20

长提示词优化5大技巧,让AI大模型更稳定可控

随着Sora、Gen-3、Midjourney V6等AI大模型的飞速发展&#xff0c;我们对AI生成内容的需求和期待已发生质的飞跃。从最初简单的“生成一张符合要求的图片”&#xff0c;升级为“创作一段有逻辑、有分镜、有质感的完整剧情”。随之而来的是Prompt的不断拉长。 长提示词带来的副…

作者头像 李华