方案概述
将18位身份证号(含校验码)压缩为48位整数(可存储在u64的低48位),布局如下:
| 字段 | 位宽 | 说明 |
|---|---|---|
addr | 20 bits | 行政区划编码(高3位=0表示非大陆,否则为大陆) |
date | 18 bits | 出生日期相对于2000-03-01的天数偏移(存储时+131072) |
seq | 10 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 bitsprov_low:省级第二位(0~6) → 3 bitscity:地级代码(01~99) → 7 bitsdistrict:县级代码(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);}