身份证号码的正则表达式及验证详解(rust版实现,Regex)

Cargo.toml

regex = "1.5.4"
# 主要用来校验润年
time = {version= "0.3.9", features = ["formatting","parsing"] }

use std::collections::HashMap;
use time::{Date, format_description};

fn main() {
    let validate = IdCardValidate::init();

    // 这个生成的身份证号符合身份证规律,但不符合润年等日期规律
    assert_eq!(generate_cert("110825199102294010").unwrap(), "11082519910229401X");

    // 不符合润年等日期规律
    assert_eq!(validate.validate_idcard("11082519910229401X"), false);
    // 不用润年日期生成一个符合的身份证号
    println!("可用的身份证号 {}", generate_cert("110825199102284010").unwrap());
    // 不用润年日期生成一个符合的身份证号,通过
    assert_eq!(validate.validate_idcard("110825199102284014"), true);
}


pub struct IdCardValidate(HashMap<i8, &'static str>);

impl IdCardValidate {
    pub fn init() -> Self {
        let mut provs = HashMap::new();
        provs.insert(11, "北京");
        provs.insert(12, "天津");
        provs.insert(13, "河北");
        provs.insert(14, "山西");
        provs.insert(15, "内蒙古");
        provs.insert(21, "辽宁");
        provs.insert(22, "吉林");
        provs.insert(23, "黑龙江");
        provs.insert(31, "上海");
        provs.insert(32, "江苏");
        provs.insert(33, "浙江");
        provs.insert(34, "安徽");
        provs.insert(35, "福建");
        provs.insert(36, "江西");
        provs.insert(37, "山东");
        provs.insert(41, "河南");
        provs.insert(42, "湖北 ");
        provs.insert(43, "湖南");
        provs.insert(44, "广东");
        provs.insert(45, "广西");
        provs.insert(46, "海南");
        provs.insert(50, "重庆");
        provs.insert(51, "四川");
        provs.insert(52, "贵州");
        provs.insert(53, "云南");
        provs.insert(54, "西藏 ");
        provs.insert(61, "陕西");
        provs.insert(62, "甘肃");
        provs.insert(63, "青海");
        provs.insert(64, "宁夏");
        provs.insert(65, "新疆");
        provs.insert(71, "台湾");
        provs.insert(81, "香港");
        provs.insert(82, "澳门");
        Self(provs)
    }

    pub fn validate_idcard(&self, cert: &str) -> bool {
        if check_code(cert) {
            let date = &cert[6..14];
            if check_date(date) {
                return self.check_prov(&cert[0..2]);
            }
        }
        false
    }

    fn check_prov(&self, prov: &str) -> bool {
        let pattern = "^[1-9][0-9]";
        validate(pattern, prov) && self.0.contains_key(&prov.parse().unwrap())
    }
}

fn check_code(cert: &str) -> bool {
    let regex = r"^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$";
    if validate(regex, cert) {
        return match check_sum(cert).map(|sum| sum.eq(&cert[17..])) {
            Ok(result) => result,
            Err(_) => false
        };
    }
    return false;
}

pub fn generate_cert(cert: &str) -> Result<String, String> {
    let regex = r"^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$";
    if validate(regex, cert) {
        return check_sum(cert).map(|sum| format!("{}{}", cert[0..17].to_string(), sum));
    }
    Err("身份证号错误".to_string())
}

fn check_date(date: &str) -> bool {
    let pattern = r#"^(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)$"#;
    if validate(pattern, date) {
        let format = format_description::parse("[year][month][day]").unwrap();
        // rust只需要验证日期正确即可排除用户随便写出19900229这样非法日期
        return Date::parse(date, &format).is_ok();
    }
    return false;
}

fn check_sum(cert: &str) -> Result<&'static str, String> {
    if cert.len() > 17 {
        let factor = [7u32, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
        let mut sum = 0;
        let mut chars = cert.chars();
        for i in 0..17 {
            sum += (chars.next().unwrap() as u32 -48) * factor[i];
        }
        let parity = ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"];
        Ok(parity[sum as usize % 11])
    } else {
        Err(format!("身份证号长度{}<18位", cert.len()))
    }
}


fn validate(pattern: &str, content: &str) -> bool {
    use regex::Regex;
    let re = Regex::new(pattern).unwrap();
    re.is_match(content)
}

#[test]
fn test(){
    let regex = r"^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$";
    // 最后一位是造的,可以过正则,但过不了身份证规律
    assert_eq!(validate(regex, "110825199102294010"),true);

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用以下正则表达式验证身份证号码的格式是否正确: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/ 这个正则表达式可以匹配满足以下条件的身份证号码: - 15位或18位数字 - 以及最后一位可以是数字或字母X(大小写均可) 这个正则表达式是通过分组和字符匹配来实现的,其中: - ^表示匹配字符串的开始 - \d表示匹配一个数字 - {15}和{18}表示匹配前面的表达式15次和18次 - $表示匹配字符串的结束 - ()用于分组,|表示或的关系 - [Xx]表示匹配字母X或x 所以,这个正则表达式可以验证符合身份证号码格式的字符串。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [js正则对身份证号的判断](https://blog.csdn.net/m0_63873004/article/details/129041876)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [身份证号码正则表达式验证详解(JavaScript,Regex)](https://blog.csdn.net/Cavendixe/article/details/129581874)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值