身份证算法

身份证生成规则:

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

地址码: 表示编码对象常住户口所在县(市、旗、区)的行政区划代码。对于新生儿,该地址码为户口登记地行政区划代码。需要没说明的是,随着行政区划的调整,同一个地方进行户口登记的可能存在地址码不一致的情况。行政区划代码按 GB/T2260 的规定执行。

出生日期码:表示编码对象出生的年、月、日,年、月、日代码之间不用分隔符,格式为YYYYMMDD,如19880328。按 GB/T 7408 的规定执行。原15位身份证号码中出生日期码还有对百岁老人特定的标识,其中999、998、997、996分配给百岁老人。

顺序码: 表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性。

校验码: 根据本体码,通过采用ISO 7064:1983.MOD 11-2校验码系统计算出校验码。算法可参考下文。前面有提到数字校验码,我们知道校验码也有X的,实质上为罗马字符X,相当于10.

校验码算法

将本体码各位数字乘以对应加权因子并求和,除以11得到余数,根据余数通过校验码对照表查得校验码。

加权因子表:
1
2
3
4
5
6
7
8
9
10

+-----------------------------------------------------------+

|位置序号|1 |2 |3 |4 |5 |6 |7 |8 |9 |10|11|12|13|14|15|16|17|

+-----------------------------------------------------------+

|加权因子|7 |9 |10|5 |8 |4 |2 |1 |6 |3 |7 |9 |10|5 |8 |4 |2 |

+-----------------------------------------------------------+
校验码表:
1
2
3
4
5
6
7
8
9
10

+----------------------------------------------------+

| 余数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

+----------------------------------------------------+

| 校验码| 1 | 0 | X | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 |

+----------------------------------------------------+
算法举例:

本体码为:44010619820202055

  • 第一步:各位数与对应加权因子乘积求和:

    $ 4 \times 7 + 4 \times 9 + 0 \times 10 + 1 \times 5 + ··· = 216$

  • 第二步:对求和结果进行除11得余数:7

    $ \bmod \ 216 - \lfloor \frac{216}{11} \rfloor \times 11 = 7 $

  • 第三步:根据余数 7 对照校验码得 5

因此完整身份证号为:440106198202020555

代码示例

Python 代码示例:

main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/env python
# -*- coding: UTF-8 -*-

def checkIDNumber(num_str):
str_to_int = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5,
'6': 6, '7': 7, '8': 8, '9': 9, 'X': 10}
check_dict = {0: '1', 1: '0', 2: 'X', 3: '9', 4: '8', 5: '7',
6: '6', 7: '5', 8: '4', 9: '3', 10: '2'}
if len(num_str) != 18:
raise TypeError(u'Please enter the standard second generation ID card number')
check_num = 0
for index, num in enumerate(num_str):
if index == 17:
right_code = check_dict.get(check_num % 11)
if num == right_code:
return [True, -1]
else:
return [False, right_code]
check_num += str_to_int.get(num) * (2 ** (17 - index) % 11)
if __name__ == '__main__':
num_str = '440106198202020555'
ret = checkIDNumber(num_str.upper())
if ret[0]:
print(u"身份证号: %s 校验通过" % num_str)
else:
print(u"身份证号: %s 校验不通过, 正确尾号应该为:%s" % (num_str, ret[1]))
评论

:D 一言句子获取中...

加载中,最新评论有1分钟缓存...