|
|
from datetime import date
|
|
|
import re # 新增正则表达式模块用于身份证验证
|
|
|
|
|
|
from astropy.version import major
|
|
|
from pyasn1_modules.rfc2985 import gender
|
|
|
|
|
|
|
|
|
class Student:
|
|
|
"""学生实体类"""
|
|
|
|
|
|
def __init__(self, stu_id: str, name: str, height: int, gender:bool or str ,major:str,birth_date: date | str,
|
|
|
enrollment_date: date | str, class_name: str, id_card: str | None = None ):
|
|
|
self.stu_id = stu_id #sid ->stu_id
|
|
|
self.name = name.strip()
|
|
|
self.height = height
|
|
|
self.birth_date = birth_date if isinstance(birth_date, date) else date.fromisoformat(birth_date)
|
|
|
self.enrollment_date = enrollment_date if isinstance(enrollment_date, date) else date.fromisoformat(
|
|
|
enrollment_date)
|
|
|
self.class_name = class_name
|
|
|
self.id_card = id_card
|
|
|
|
|
|
self.gender=gender
|
|
|
self.major=major
|
|
|
|
|
|
self._validation_errors = []
|
|
|
self._validate_height()
|
|
|
self._validate_dates()
|
|
|
self._validate_name()
|
|
|
self._validate_id_card()
|
|
|
|
|
|
|
|
|
|
|
|
def _validate_id_card(self) -> None:
|
|
|
"""验证身份证格式,包括校验码检验"""
|
|
|
if not self.id_card:
|
|
|
return
|
|
|
if len(self.id_card)!=18:
|
|
|
self._validation_errors.append("身份证号长度应为18位")
|
|
|
if not self.id_card[:17].isdigit():
|
|
|
self._validation_errors.append("身份证号前17位必须为数字")
|
|
|
weights = [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']
|
|
|
|
|
|
total = sum(int(self.id_card[i]) * weights[i] for i in range(17))
|
|
|
expected_check = check_codes[total % 11]
|
|
|
if self.id_card[-1].upper()!=expected_check:
|
|
|
self._validation_errors.append("校验码不匹配,身份证格式不正确")
|
|
|
|
|
|
# 从身份证提取出生日期并验证
|
|
|
try:
|
|
|
if len(self.id_card) == 18:
|
|
|
birth_year = int(self.id_card[6:10])
|
|
|
birth_month = int(self.id_card[10:12])
|
|
|
birth_day = int(self.id_card[12:14])
|
|
|
extracted_birth_date = date(birth_year, birth_month, birth_day)
|
|
|
if extracted_birth_date != self.birth_date:
|
|
|
self._validation_errors.append("身份证出生日期与登记出生日期不一致")
|
|
|
except (ValueError, IndexError):
|
|
|
self._validation_errors.append("身份证日期解析失败")
|
|
|
gender_code=int(self.id_card[16])
|
|
|
gender="男"if gender_code % 2==1 else "女"
|
|
|
self.gender=gender
|
|
|
|
|
|
def _validate_height(self) -> None:
|
|
|
if not (50 <= self.height <= 250):
|
|
|
self._validation_errors.append(f"身高{self.height}cm超出合理范围(50-250厘米)")
|
|
|
|
|
|
def _validate_name(self) -> None:
|
|
|
if not (2 <= len(self.name) <= 20):
|
|
|
self._validation_errors.append("姓名长度需要在2到20个字符以内")
|
|
|
if not self.name.isprintable():
|
|
|
self._validation_errors.append("姓名包含不可打印的字符")
|
|
|
|
|
|
def _validate_dates(self) -> None:
|
|
|
today = date.today()
|
|
|
if self.birth_date > today:
|
|
|
self._validation_errors.append("出生日期不能在未来")
|
|
|
if self.enrollment_date > today:
|
|
|
self._validation_errors.append("入学日期不能在未来")
|
|
|
if self.birth_date > self.enrollment_date:
|
|
|
self._validation_errors.append("入学日期不能早于出生日期")
|
|
|
|
|
|
@property
|
|
|
def is_valid(self) -> bool:
|
|
|
return len(self._validation_errors) == 0
|
|
|
|
|
|
def get_errors(self) -> list[str]:
|
|
|
return self._validation_errors.copy()
|
|
|
|
|
|
def __eq__(self, other) -> bool:
|
|
|
if not isinstance(other, Student):
|
|
|
return NotImplemented
|
|
|
return (self.stu_id == other.stu_id and self.name == other.name and self.height == other.height and
|
|
|
self.birth_date == other.birth_date and self.enrollment_date == other.enrollment_date and
|
|
|
self.class_name == other.class_name and self.id_card == other.id_card)
|
|
|
|
|
|
def to_dict(self) -> dict:
|
|
|
"""将对象序列化为字典"""
|
|
|
return {
|
|
|
'stu_id': self.stu_id,
|
|
|
'name': self.name,
|
|
|
'height': self.height,
|
|
|
'birth_date': self.birth_date.isoformat(),
|
|
|
'enrollment_date': self.enrollment_date.isoformat(),
|
|
|
'class_name': self.class_name,
|
|
|
'id_card': self.id_card, # 新增身份证字段
|
|
|
'gender':self.gender, # 新增性别
|
|
|
'major':self.major # 新增专业
|
|
|
}
|
|
|
|
|
|
@classmethod
|
|
|
def from_dict(cls, data: dict) -> 'Student':
|
|
|
"""从字典创建对象(自动处理日期解析)"""
|
|
|
birth_date = data['birth_date']
|
|
|
enrollment_date = data['enrollment_date']
|
|
|
birth_date = birth_date if isinstance(birth_date, date) else date.fromisoformat(birth_date)
|
|
|
enrollment_date = enrollment_date if isinstance(enrollment_date, date) else date.fromisoformat(enrollment_date)
|
|
|
# 从字典获取身份证(允许为空)
|
|
|
id_card = data.get('id_card')
|
|
|
return cls(
|
|
|
stu_id=data['stu_id'],
|
|
|
name=data['name'].strip(),
|
|
|
height=data['height'],
|
|
|
birth_date=birth_date,
|
|
|
enrollment_date=enrollment_date,
|
|
|
class_name=data['class_name'],
|
|
|
id_card=id_card, # 传递身份证参数
|
|
|
gender=data['gender'],
|
|
|
major= data ['major']
|
|
|
)
|
|
|
|
|
|
def __repr__(self) -> str:
|
|
|
"""完整对象表示(包含所有字段信息)"""
|
|
|
return (
|
|
|
f"{self.__class__.__name__}("
|
|
|
f"stu_id='{self.stu_id}', "
|
|
|
f"name='{self.name}', "
|
|
|
f"height={self.height}, "
|
|
|
f"birth_date=date({self.birth_date.year}, {self.birth_date.month}, {self.birth_date.day}), "
|
|
|
f"enrollment_date=date({self.enrollment_date.year}, {self.enrollment_date.month}, {self.enrollment_date.day}), "
|
|
|
f"class_name='{self.class_name}', "
|
|
|
f"id_card='{self.id_card}',"
|
|
|
f"gender='{self.gender}',"
|
|
|
f"major='{self.major}'"
|
|
|
f")"
|
|
|
)
|
|
|
|
|
|
|