测试身份证校验时遇到过这样需求:
- 身份证规则校验:前端校验长度、合法生日、第18位校验码、年龄18-80岁等
- 身份证真实性校验:后台调用第三方服务校验
对于需求1,长度、合法生日都比较好造数据,但第18位校验码得按照特定规则来生成:
- 第1-6位:行政区划代码,可在国家统计局官网上获得。
- 第7-14位:出生年月日。
- 第15-16位:派出所代码。
- 第17位:性别,偶女奇男。
- 第18位:校检码,前17位数与17位加权因子 [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2] 相乘求和,除以11取余,得到索引,通过索引在列表 ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'] 中得到的值,即为第18位校验码。
以下为Python实现的代码:
1 # coding=utf-8 2 import ConfigParser 3 import getopt 4 import sys 5 import random 6 import time 7 8 9 def id_card(): 10 def division_code(): 11 u""" 12 随机返回ini文件保存的行政区划代码 13 :return: 行政区划代码 14 """ 15 config = ConfigParser.ConfigParser() 16 config.read('division_code.ini') 17 divisions = config.items('division_code') 18 return random.choice(divisions)[0] 19 20 def birth_code(age): 21 u""" 22 根据年龄返回生日,月日写死了为0101,^_^ 23 :param age: 年龄 24 :return: 生日年月日 25 """ 26 cur_year = time.strftime('%Y', time.localtime()) 27 birth_year = int(cur_year) - int(age) 28 return '%s0101' % birth_year 29 30 def check_code(pre_17_code): 31 u""" 32 根据前17位生成第18位校验码 33 :param pre_17_code: 前17位 34 :return: 校验码 35 """ 36 # 加权因子 37 powers = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; 38 # 校验码列表 39 check_codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']; 40 check_code_index = sum(map(lambda (pre, power): int(pre) * power, zip(pre_17_code, powers))) % 11 41 return check_codes[check_code_index] 42 43 age = random.randint(1, 100) 44 _gender_code = str(random.randint(0, 9)) 45 46 u""" 47 命令行参数,选填 48 """ 49 opts, args = getopt.getopt(sys.argv[1:], 'ha:g:', ['help', 'age=', 'gender=']) 50 for opt, value in opts: 51 if opt in ['-a', '--age']: 52 age = value 53 elif opt in ['-g', '--gender']: 54 _gender_code = value 55 elif opt in ['-h', '--help']: 56 print u''' 57 -a <age> 58 --age <age> 年龄:18 59 -g <gender> 60 --gender <gender> 性别:0-9,奇数男、偶数女女 61 -h 62 --help 说明 ''' 63 sys.exit() 64 65 _division_code = division_code() 66 _birth_code = birth_code(age) 67 _police_code = str(random.randint(0, 9)).rjust(2, '0') 68 pre_17_code = _division_code + _birth_code + _police_code + _gender_code 69 _check_code = check_code(pre_17_code) 70 code = pre_17_code + _check_code 71 print u'身份证号:%s,性别:%s,年龄:%s' % (code, u'女' if int(_gender_code) / 2 == 0 else u'男', age) 72 return code 73 74 if __name__ =='__main__': 75 id_card()
执行结果:
>python id_card.py 身份证号:110100201201010726,性别:男,年龄:5 >python id_card.py --age 80 --gender 9 身份证号:11010019370101059X,性别:男,年龄:80
对于需求2,可通过假接口或后台开关来控制。