| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- """
- 身份证号验证服务
- 提供严格的身份证号码校验,包括:
- - 格式校验(18位)
- - 出生日期校验
- - 校验码验证(ISO 7064:1983.MOD 11-2)
- """
- import re
- from datetime import datetime
- class IDCardValidator:
- """身份证号验证器"""
-
- # 加权因子
- WEIGHT_FACTORS = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
-
- # 校验码对应值
- CHECK_CODES = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
-
- @staticmethod
- def validate_format(id_card: str) -> tuple[bool, str]:
- """
- 验证身份证号格式
-
- Returns:
- (是否有效, 错误信息)
- """
- # 必须是18位
- if len(id_card) != 18:
- return False, "身份证号必须为18位"
-
- # 前17位必须是数字,最后一位是数字或X
- if not re.match(r'^\d{17}[\dXx]$', id_card):
- return False, "身份证号格式不正确"
-
- return True, ""
-
- @staticmethod
- def validate_birth_date(id_card: str) -> tuple[bool, str]:
- """
- 验证出生日期
-
- Args:
- id_card: 18位身份证号
-
- Returns:
- (是否有效, 错误信息)
- """
- # 提取出生日期(第7-14位)
- year = id_card[6:10]
- month = id_card[10:12]
- day = id_card[12:14]
-
- # 验证年份(1900-当前年份)
- try:
- year_int = int(year)
- current_year = datetime.now().year
- if year_int < 1900 or year_int > current_year:
- return False, f"出生年份不合法(应在1900-{current_year}之间)"
- except ValueError:
- return False, "出生年份格式错误"
-
- # 验证月份(01-12)
- try:
- month_int = int(month)
- if month_int < 1 or month_int > 12:
- return False, "出生月份不合法(应在01-12之间)"
- except ValueError:
- return False, "出生月份格式错误"
-
- # 验证日期
- try:
- birth_date = datetime(year_int, month_int, int(day))
-
- # 不能是未来日期
- if birth_date > datetime.now():
- return False, "出生日期不能是未来日期"
-
- except ValueError:
- return False, "出生日期不合法"
-
- return True, ""
-
- @staticmethod
- def validate_check_code(id_card: str) -> tuple[bool, str]:
- """
- 验证校验码(ISO 7064:1983.MOD 11-2)
-
- Args:
- id_card: 18位身份证号
-
- Returns:
- (是否有效, 错误信息)
- """
- # 计算校验码
- sum_value = 0
- for i in range(17):
- sum_value += int(id_card[i]) * IDCardValidator.WEIGHT_FACTORS[i]
-
- # 取模得到校验码索引
- check_index = sum_value % 11
- expected_check_code = IDCardValidator.CHECK_CODES[check_index]
-
- # 比较校验码(不区分大小写)
- actual_check_code = id_card[17].upper()
- if actual_check_code != expected_check_code:
- return False, f"身份证号校验码错误"
-
- return True, ""
-
- @classmethod
- def validate(cls, id_card: str) -> tuple[bool, str]:
- """
- 完整验证身份证号
-
- Args:
- id_card: 身份证号
-
- Returns:
- (是否有效, 错误信息)
- """
- # 转大写
- id_card = id_card.upper().strip()
-
- # 格式验证
- valid, error = cls.validate_format(id_card)
- if not valid:
- return False, error
-
- # 出生日期验证
- valid, error = cls.validate_birth_date(id_card)
- if not valid:
- return False, error
-
- # 校验码验证
- valid, error = cls.validate_check_code(id_card)
- if not valid:
- return False, error
-
- return True, ""
- def validate_real_name(name: str) -> tuple[bool, str]:
- """
- 验证真实姓名
-
- Args:
- name: 姓名
-
- Returns:
- (是否有效, 错误信息)
- """
- # 去除首尾空格
- name = name.strip()
-
- # 长度验证(2-20位)
- if len(name) < 2 or len(name) > 20:
- return False, "姓名长度应为2-20个字符"
-
- # 纯汉字验证(不允许特殊符号、空格)
- if not re.match(r'^[\u4e00-\u9fa5]+$', name):
- return False, "姓名只能包含汉字,不能有空格或特殊符号"
-
- return True, ""
|