id_card/
lib.rs

1// #![deny(missing_docs)]
2extern crate regex;
3#[macro_use]
4extern crate lazy_static;
5
6mod region;
7
8use chrono::NaiveDate;
9use regex::Regex;
10
11pub fn validate(id_number: &str) -> bool {
12    let id_pattern = Regex::new(r"[1-9][0-9]{14}[0-9]{2}[0-9Xx]").unwrap();
13    if id_pattern.is_match(id_number) == false {
14        return false;
15    }
16    //check region code
17    // let region_code: String = id_number.chars().take(6).collect();
18    if !region::validate_code(&id_number[0..6]) {
19        return false;
20    }
21    //check date
22    let birth_date = NaiveDate::parse_from_str(&id_number[6..14], "%Y%m%d");
23    if !birth_date.is_ok() {
24        return false;
25    }
26
27    let mut id_number_string = id_number.to_string();
28    let check_code = id_number_string.pop().unwrap();
29    //transform the chars except the last to u32
30    let items: Vec<u32> = id_number_string
31        .chars()
32        .map(|c| c.to_digit(10).unwrap())
33        .collect();
34    let factors: [u32; 17] = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
35    let mut sum = 0u32;
36    for (&x, &y) in items.iter().zip(&factors) {
37        sum += x * y;
38    }
39    let verify_code_expected = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
40    let modulo = sum % 11;
41    return verify_code_expected[modulo as usize] == check_code.to_ascii_uppercase();
42}