id_card_validator.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. """
  2. 身份证号验证服务
  3. 提供严格的身份证号码校验,包括:
  4. - 格式校验(18位)
  5. - 出生日期校验
  6. - 校验码验证(ISO 7064:1983.MOD 11-2)
  7. """
  8. import re
  9. from datetime import datetime
  10. class IDCardValidator:
  11. """身份证号验证器"""
  12. # 加权因子
  13. WEIGHT_FACTORS = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
  14. # 校验码对应值
  15. CHECK_CODES = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
  16. @staticmethod
  17. def validate_format(id_card: str) -> tuple[bool, str]:
  18. """
  19. 验证身份证号格式
  20. Returns:
  21. (是否有效, 错误信息)
  22. """
  23. # 必须是18位
  24. if len(id_card) != 18:
  25. return False, "身份证号必须为18位"
  26. # 前17位必须是数字,最后一位是数字或X
  27. if not re.match(r'^\d{17}[\dXx]$', id_card):
  28. return False, "身份证号格式不正确"
  29. return True, ""
  30. @staticmethod
  31. def validate_birth_date(id_card: str) -> tuple[bool, str]:
  32. """
  33. 验证出生日期
  34. Args:
  35. id_card: 18位身份证号
  36. Returns:
  37. (是否有效, 错误信息)
  38. """
  39. # 提取出生日期(第7-14位)
  40. year = id_card[6:10]
  41. month = id_card[10:12]
  42. day = id_card[12:14]
  43. # 验证年份(1900-当前年份)
  44. try:
  45. year_int = int(year)
  46. current_year = datetime.now().year
  47. if year_int < 1900 or year_int > current_year:
  48. return False, f"出生年份不合法(应在1900-{current_year}之间)"
  49. except ValueError:
  50. return False, "出生年份格式错误"
  51. # 验证月份(01-12)
  52. try:
  53. month_int = int(month)
  54. if month_int < 1 or month_int > 12:
  55. return False, "出生月份不合法(应在01-12之间)"
  56. except ValueError:
  57. return False, "出生月份格式错误"
  58. # 验证日期
  59. try:
  60. birth_date = datetime(year_int, month_int, int(day))
  61. # 不能是未来日期
  62. if birth_date > datetime.now():
  63. return False, "出生日期不能是未来日期"
  64. except ValueError:
  65. return False, "出生日期不合法"
  66. return True, ""
  67. @staticmethod
  68. def validate_check_code(id_card: str) -> tuple[bool, str]:
  69. """
  70. 验证校验码(ISO 7064:1983.MOD 11-2)
  71. Args:
  72. id_card: 18位身份证号
  73. Returns:
  74. (是否有效, 错误信息)
  75. """
  76. # 计算校验码
  77. sum_value = 0
  78. for i in range(17):
  79. sum_value += int(id_card[i]) * IDCardValidator.WEIGHT_FACTORS[i]
  80. # 取模得到校验码索引
  81. check_index = sum_value % 11
  82. expected_check_code = IDCardValidator.CHECK_CODES[check_index]
  83. # 比较校验码(不区分大小写)
  84. actual_check_code = id_card[17].upper()
  85. if actual_check_code != expected_check_code:
  86. return False, f"身份证号校验码错误"
  87. return True, ""
  88. @classmethod
  89. def validate(cls, id_card: str) -> tuple[bool, str]:
  90. """
  91. 完整验证身份证号
  92. Args:
  93. id_card: 身份证号
  94. Returns:
  95. (是否有效, 错误信息)
  96. """
  97. # 转大写
  98. id_card = id_card.upper().strip()
  99. # 格式验证
  100. valid, error = cls.validate_format(id_card)
  101. if not valid:
  102. return False, error
  103. # 出生日期验证
  104. valid, error = cls.validate_birth_date(id_card)
  105. if not valid:
  106. return False, error
  107. # 校验码验证
  108. valid, error = cls.validate_check_code(id_card)
  109. if not valid:
  110. return False, error
  111. return True, ""
  112. def validate_real_name(name: str) -> tuple[bool, str]:
  113. """
  114. 验证真实姓名
  115. Args:
  116. name: 姓名
  117. Returns:
  118. (是否有效, 错误信息)
  119. """
  120. # 去除首尾空格
  121. name = name.strip()
  122. # 长度验证(2-20位)
  123. if len(name) < 2 or len(name) > 20:
  124. return False, "姓名长度应为2-20个字符"
  125. # 纯汉字验证(不允许特殊符号、空格)
  126. if not re.match(r'^[\u4e00-\u9fa5]+$', name):
  127. return False, "姓名只能包含汉字,不能有空格或特殊符号"
  128. return True, ""