use std::sync::LazyLock;
use regex::Regex;
static SSN_PATTERN: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"\b(\d{3})-(\d{2})-(\d{4})\b").expect("SSN pattern is a valid regex")
});
#[must_use]
pub fn is_valid_format(ssn: &str) -> bool {
SSN_PATTERN.is_match(ssn)
}
#[must_use]
pub fn is_valid_range(ssn: &str) -> bool {
if let Some(caps) = SSN_PATTERN.captures(ssn) {
let area: u16 = caps[1].parse().unwrap_or(0);
let group: u16 = caps[2].parse().unwrap_or(0);
let serial: u16 = caps[3].parse().unwrap_or(0);
if area == 0 || area == 666 || area >= 900 {
return false;
}
if group == 0 || serial == 0 {
return false;
}
true
} else {
false
}
}
#[must_use]
pub fn mask(ssn: &str) -> String {
if let Some(caps) = SSN_PATTERN.captures(ssn) {
format!("XXX-XX-{}", &caps[3])
} else {
"XXX-XX-XXXX".to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn valid_format() {
assert!(is_valid_format("123-45-6789"));
assert!(!is_valid_format("123456789"));
}
#[test]
fn valid_range() {
assert!(is_valid_range("123-45-6789"));
assert!(!is_valid_range("000-45-6789"));
assert!(!is_valid_range("666-45-6789"));
assert!(!is_valid_range("900-45-6789"));
}
#[test]
fn mask_ssn() {
assert_eq!(mask("123-45-6789"), "XXX-XX-6789");
}
}