身份证号码校验

# -*- coding: utf-8 -*-
"""
@Time    : 2021/9/9 15:00
@Author  : Little Duo
@File    : IDCardTools.py
http://www.mca.gov.cn/article/sj/xzqh/1980/
"""

import time
import random
from data import Area
from enum import Enum
from pydantic import BaseModel


class Verification(Enum):
    PASSED = '验证通过'
    LENGTH_ERROR = '身份证号码长度错误'
    BIRTH_ERROR = '身份证号码出生日期校验错误'
    VERITYCODE_ERROR = '身份证号码校验码错误'
    AREACODE_ERROR = '身份证地区非法'
    NULL_ERROR = '身份证号码不能为空'


class Result(BaseModel):
    success: bool = True
    desc: str


def calculVerityCode(seventeenIdCard):
    """
    计算校验码
    :param seventeenIdCard: 17位身份证号码
    :return:
    """
    i = 0
    count = 0
    weight = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]  # 权重项
    checkcode = {'0': '1', '1': '0', '2': 'X', '3': '9', '4': '8', '5': '7', '6': '6', '7': '5', '8': '5', '9': '3',
                 '10': '2'}
    for i in range(0, 17):
        count = count + int(seventeenIdCard[i]) * weight[i]
    return checkcode[str(count % 11)]  # 算出校验码


def checkIDCard(idCard: str):
    """
    身份证号码校验(仅限大陆)

    :param idCard:
    :return:
    """
    # 身份证号码位数校验
    if len(idCard) not in (15, 18):
        return Result(success=False, desc=Verification.LENGTH_ERROR.name)

    # 地区校验
    province = Area.province()
    idCardList = list(idCard)
    if idCard[0:2] not in province.keys():
        return Result(success=False, desc=Verification.AREACODE_ERROR.name)

    # 出生日期校验
    birthday = '19{}'.format(idCard[6:-3]) if len(idCard) == 15 else idCard[6:-4]
    try:
        year = time.strptime(birthday, '%Y%m%d').tm_year
        if year >= time.localtime().tm_year or year < 1900:
            raise ValueError
    except ValueError:
        return Result(success=False, desc=Verification.BIRTH_ERROR.name)

    if idCard[17] != calculVerityCode(idCard[:17]):
        return Result(success=False, desc=Verification.VERITYCODE_ERROR.name)

    return Result(desc=Verification.PASSED.name)


def gennerator(areaCode, year, month, day, gend):
    """

    :param areaCode: 地区编码
    :param year: 出生年
    :param month: 出生月
    :param day: 出生日
    :param gend: 性别 1男2女
    :return:
    """
    gendCode = random.choice([0, 2, 4, 6, 8]) if int(gend) > 1 else random.choice([1, 3, 5, 7, 9])
    idCard = '{}{}{}{}{}{}'.format(areaCode, year, month, day, random.randint(10, 99), gendCode)
    idCard = idCard + calculVerityCode(idCard)
    return idCard


def upEighteen(fifteenIDCard):
    """
    15位转18位

    :param fifteenIDCard:
    :return:
    """
    checkIDCarded = checkIDCard(fifteenIDCard)
    if not checkIDCarded.success:
        return checkIDCarded
    seventeenIDCard = fifteenIDCard[0:6] + '19' + fifteenIDCard[6:15]
    return seventeenIDCard + calculVerityCode(seventeenIDCard)


def downFifteen(eighteenIDCard):
    """
    18位转15位

    :param eighteenIDCard:18位身份证号码
    :return:
    """
    checkIDCarded = checkIDCard(eighteenIDCard)
    if not checkIDCarded.success:
        return checkIDCarded
    return eighteenIDCard[0:6] + eighteenIDCard[8:17]
posted @ 2023-02-28 14:31  LittleDuo  阅读(47)  评论(0)    收藏  举报