解析身份证号码(Python版)

解析身份证号码(Python版)

  • 简单分析
    • 结构
      • 六位数字地址码
      • 八位数字出生日期码
      • 三位数字顺序码
      • 一位数字校验码
  • 代码实现
    • 获取身份证号里的信息
    • 获取身份证中的省份
    • 计算身份证校验位
    • 验证并提取信息

简单分析

结构

我国的居民身份证号码是特征组合码,由十七位数字本体码和一位校验码组成。
排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位数字校验码。

六位数字地址码

第一、二位表示省级行政区。
第一位数字是以前的大区制代码。第二位是大区所在省市编码。

  1. 华北三省二市
  2. 东北三省
  3. 华东六省一市
  4. 华中华南六省
  5. 西南四省一市
  6. 西北五省
  7. 台湾省
  8. 香港澳门

具体省(直辖市,自治区,特别行政区)编码如下

  • 11~15 京津冀晋蒙
  • 21~23 辽吉黑
  • 31~37 沪苏浙皖闽赣鲁
  • 41~46 豫鄂湘粤桂琼
  • 50~54 渝川贵云藏
  • 61~65 陕甘青宁新
  • 71 台湾
  • 81~82 港澳

记不住省份简称的可以跳过去看看
https://blog.csdn.net/qq_55342245/article/details/113815397

第一位表示区域码,第二位表示该区域内的省的编码。
引入区域的概念后,既保持了各省代码的相对连续,又方便了以后对省级行政区划变更的扩展。
比如重庆市以前是隶属于四川省的一个省辖市,升级为直辖市后,新的代码就从西南区域中分配(新分配到的区划代码是50)。假如以后深圳市也有机会升级为直辖市的话,就可以从华南区域分配省级区划代码(比如40)。目前各区域都预留有4~7个代码作为备用。
在一个区域内,编码的顺序是有个优先级的:直辖市,省,自治区。

第三、四位表示市、地区、自治州、盟、直辖市所辖市辖区/县汇总码、省(自治区)直辖县级行政区划汇总码。01一般表示本省省会。其中:

  • 01~20/51~70表示市,01、02还用与表示直辖市所辖市辖区/县汇总码;
  • 21~50表示地区、自治州、盟;
  • 90表示省(自治区)直辖县级行政区划汇总码。
    解析身份证号码(Python版)_第1张图片

例如车牌,A表示本省省会,B一般是本省的二线城市
辽A是沈阳 辽B是大连,黑A是哈尔滨 黑B是齐齐哈尔,川A是成都 川B是绵阳,云A是昆明 云南没有B的牌照

第五、六位表示县、自治县、县级市、旗、自治旗、市辖区、林区、特区。01一般表示本市市辖区。其中:

  • 01~20表示市辖区、地区(自治州、盟)辖县级市、市辖特区以及省(自治区)直辖县级行政区划中的县级市,01通常表示市辖区汇总码;
  • 21~80表示县、自治县、旗、自治旗、林区、地区辖特区;
  • 81~99表示省(自治区)辖县级市。
    解析身份证号码(Python版)_第2张图片

210101辽宁省沈阳市市辖区 210201辽宁省大连市市辖区
230101黑龙江省哈尔滨市市辖区 230201黑龙江省齐齐哈尔市市辖区
510101四川省成都市市辖区 510701四川省绵阳市市辖区


八位数字出生日期码

(身份证号码第七位到第十四位)表示编码对象出生的年、月、日,其中年份用四位数字表示,年、月、日之间不用分隔符。例如:1981年05月11日就用19810511表示。

三位数字顺序码

(身份证号码第十五位到十七位)表示在同一地址码所标识的区域范围内,对同年、月、日出生的人员编定的顺序号。其中第十七位奇数分给男性,偶数分给女性。(我国古代,奇数为阳,偶数为阴)

一位数字校验码

根据前面十七位数字码,按一定规则计算出来。

简单版
W里包含17个数,W = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]。
用身份证号的前17位分别对应相乘。从左往右数,第一位乘7,第二位乘9,第三位乘10,,然后将这些结果求和,用和除以11得到一个余数。
REM里包含11个数,REM = [‘1’, ‘0’, ‘X’, ‘9’, ‘8’, ‘7’, ‘6’, ‘5’, ‘4’, ‘3’, ‘2’]。
余数是0,那么最后一位是1;余数是1,那么最后一位是0;余数是2,那么最后一位是X。。。以此类推

专业版
公式:最后一位 = ( 12 − ∑ i = 2 18 a i w i   m o d   11 )   m o d   11 = ( 12- \sum_{i=2}^{18}a_{i}w_{i} \ mod \ 11) \ mod \ 11 =(12i=218aiwi mod 11) mod 11

ai 是从右往左数第i位,加权因子 wi = 2(i-1) mod 11
身份证是18位,所以a2指倒数第二位,正数第17位;a3指倒数第三位,正数第16位
mod 是取余数的意思。 例(36 mod 5)=1(36/5=7余1), (46 mod 8)=6(46/8=5余6)

因为最后一位是除以11取余数得到,就有0~10这十一种情况,那么就得用X(X是罗马数字的10)来代替10,因为如果用10做尾号,那么此人的身份证就变成了19位,而19位的号码违反了国家标准。

十八位身份证还可以用这个公式验证: ∑ i = 1 18 a i w i ≡ 1 ( m o d 11 ) \sum_{i=1}^{18}a_{i}w_{i} \equiv 1 ( mod 11) i=118aiwi1(mod11)

这个公式的另一种写法是: ( ∑ i = 1 18 a i w i ) m o d 11 = 1 ( \sum_{i=1}^{18}a_{i}w_{i}) mod 11 = 1 (i=118aiwi)mod11=1

≡ \equiv ”是同余符号。 例:
16 ≡ \equiv 11 ( mod 5)     16除以5=3余1,11除以5=2余1。余数都是1,二者同余
25 ≡ \equiv 3 ( mod 11)     25除以11=2余3,3除以11=0余3。余数都是3,二者同余

安利几个千年难遇的身份证号(虽然合法,但不一定真实存在。如有冒犯请联系删除)
这些身份证是有意义的。但形成这样的身份证号,必须是公安机关分配给你的顺序码由0和2组成,而且0和2的还得有一个正确的搭配顺序
220202200002022002 吉林省吉林市昌邑区2000年2月2日出生的女孩
220202200002200200 吉林省吉林市昌邑区2000年2月20日出生的女孩
220202202002020022 吉林省吉林市昌邑区2020年2月2日出生的女孩
220202202002022220 吉林省吉林市昌邑区2020年2月2日出生的女孩
220202202002202002 吉林省吉林市昌邑区2020年2月20日出生的女孩

def doVerify(id):
    sum = 0
    # 身份证的前十七位分别乘以相应的加权因子
    wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    for i in range(17):
        sum += int(id[i]) * wi[i]
    j = sum%11
    # 根据余数去匹配对应的数字
    rem = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
    # print("校验码是:" + rem[j])
    if id[17]==rem[j]:
        return True
    else:
        return False

li = []

area = '220202'
year = ['2000','2002','2020','2022']
month = '02'
day = ['02','20','22']
num = ['002','020','022','200','202','220','222']
mo = ['0','2']

for y in year:
    for d in day:
        for n in num:
            for m in mo:
                id = area + y + month + d + n + m
                if doVerify(id):
                    li.append(id)

print(li)
print(len(li))

代码实现

获取身份证号里的信息

def getInfo(s):
    area = s[0:6]
    year = s[6:10]
    month = s[10:12]
    day = s[12:14]
    num = s[14:17]
    checkCode = s[17]

    print("地区码:" + area)
    print(f"出生日期:{year}{month}{day}日")
    print("顺序码:" + num)
    print("校验码:" + checkCode)
    print("性别:女") if int(num) % 2 == 0 else print("性别:男")


id = '510107199806186520'
getInfo(id)

获取身份证中的省份

def getArea(s):
    area = {"11":"北京市", "12":"天津市", "13":"河北省", "14":"山西省", "15": "内蒙古自治区",
            "21":"辽宁省", "22":"吉林省", "23":"黑龙江省",
            "31":"上海市", "32":"江苏省", "33":"浙江省", "34":"安徽省", "35":"福建省", "36":"江西省", "37":"山东省",
            "41":"河南省", "42":"湖北省", "43":"湖南省", "44":"广东省", "45":"广西壮族自治区", "46":"海南省",
            "50":"重庆市", "51":"四川省", "52":"贵州省", "53":"云南省", "54":"西藏自治区",
            "61":"陕西省", "62":"甘肃省", "63":"青海省", "64":"宁夏回族自治区", "65":"新疆维吾尔自治区",
            "71":"台湾省",
            "81":"香港特别行政区", "82":"澳门特别行政区"}

    if s[0:2] in area.keys():
        print(area[s[0:2]])
    else:
        print('地区码无效')

id = '510107199806186520'
getArea(id)

计算身份证校验位

简单的

# (简单)
def doVerify(id):
    sum = 0
    # 身份证的前十七位分别乘以相应的加权因子
    wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
    # 根据余数去匹配对应的数字
    rem = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']

    for i in range(17):
        sum += int(id[i]) * wi[i]
    print("校验码是:" + rem[sum%11] )

id = '11223223239811110'
doVerify(id)

专业的
公式:最后一位 = ( 12 − ∑ i = 2 18 a i w i   m o d   11 )   m o d   11 = ( 12- \sum_{i=2}^{18}a_{i}w_{i} \ mod \ 11) \ mod \ 11 =(12i=218aiwi mod 11) mod 11

def Judge(id):
    sum = 0
    for i in range(17):
        # 加权因子wi = 2^(i-1) mod 11  i从右往左数
        # 也就是w1 = (2^17) % 11,w2 = (2^16) % 11,w17 = (2^1) % 11
        wi = 1
        wi <<= 17-i # 左移,这里相当于乘以2的(17-i)次方
        wi %= 11    # 计算得到最终的加权因子

        sum += int(id[i]) * wi
    print(f"校验码是:{(12-sum%11)%11}")

id = '9153455276589485465110'
Judge(id)

验证并提取信息

import datetime
now = datetime.datetime.now()
now = str(now)


# 判断身份证号检验码
def Judge(id):
    sum = 0
    for i in range(17):
        # 加权因子wi = 2^(i-1) mod 11  i从右往左数
        # 也就是w1 = (2^17) % 11,w2 = (2^16) % 11,w17 = (2^1) % 11
        wi = 1
        wi <<= 17-i # 左移,这里相当于乘以2的(17-i)次方
        wi %= 11    # 计算得到最终的加权因子
        sum += int(id[i]) * wi
    mo = (12-sum%11)%11
    if id[17] == str(mo) or ((id[17]=='x' or id[17]=='X') and mo==10):
        return True


# 判断身份证号地区码
def Area(id):
    area = {"11":"北京市", "12":"天津市", "13":"河北省", "14":"山西省", "15": "内蒙古自治区",
            "21":"辽宁省", "22":"吉林省", "23":"黑龙江省",
            "31":"上海市", "32":"江苏省", "33":"浙江省", "34":"安徽省", "35":"福建省", "36":"江西省", "37":"山东省",
            "41":"河南省", "42":"湖北省", "43":"湖南省", "44":"广东省", "45":"广西壮族自治区", "46":"海南省",
            "50":"重庆市", "51":"四川省", "52":"贵州省", "53":"云南省", "54":"西藏自治区",
            "61":"陕西省", "62":"甘肃省", "63":"青海省", "64":"宁夏回族自治区", "65":"新疆维吾尔自治区",
            "71":"台湾省",
            "81":"香港特别行政区", "82":"澳门特别行政区"}
    if id[0:2] in area.keys():
        return area[id[0:2]]
    else:
        return ''


# 判断时间是否合法
def Year(id):
    y = int(id[6:10])
    if y>=1840 and y<=int(now[0:4]):
        return True
    else:
        return False

def Month(id):
    m = int(id[10:12])
    if m>=1 and m<=12:
        return True
    else:
        return False

def Day(id):
    y = int(id[6:10])
    m = int(id[10:12])
    d = int(id[12:14])
    if m >= 1 and m <= 12:
        if m in [1,3,5,7,8,10,12]:
            if d>=1 and d<=31:
                return True
        if m in [4,6,9,11]:
            if d>=1 and d<=30:
                return True
        if m==2:
            if y%4==0 and y%100!=0 or y%400==0:
                if d>=1 and d<=29:
                    return True
            else:
                if d>=1 and d<=28:
                    return True
    else:
        return False


if __name__ == '__main__':
    id = '220202200002022002'
    id = '220202202002022220'
    area = Area(id)
    if len(id)==18 and id[:17].isdigit() and Judge(id) and len(area)!=0 and Year(id) and Month(id) and Day(id):
        print("身份证号有效")
        print(f"地区码:{id[0:6]},属于{area}")
        print(f"出生日期:{id[6:10]}{id[10:12]}{id[12:14]}日")
        print("顺序码:" + id[14:17])
        print("校验码:" + id[17])
        print("性别:女") if int(id[16]) % 2 == 0 else print("性别:男")
    else:
        print('输入有误,该身份证不合法。。。')

你可能感兴趣的:(Python,数学,python)