用Python计算身份证校验码

来源:互联网 发布:wps表格筛选重复数据 编辑:程序博客网 时间:2024/05/05 00:16

转自:http://my.oschina.net/moooofly/blog/147958

原来的天朝良民证是15位,构成如下: 
1~6位:地址码。采用的是行政区划代码,可以去 统计局的网站 查。 
7~12位:生日期码。构成为yymmdd。 
13~15位:顺序码。每个地区出生人口按顺序递增,最后一位奇数分给男的,偶数分给女的。 

18位则有2点改动: 
1.生日期码变为8位,构成为yyyymmdd。 
2.增加校验码,即第18位。按照ISO 7064:1983.MOD 11-2校验码计算。 

计算方法很无聊: 

  1. 将身份证号码的前17位数分别乘以不同的系数。从第一位到第十七位的系数分别为:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 
  2. 将这17位数字和系数相乘的结果相加。
  3. 用加出来和除以11,得到余数。
  4. 余数的结果只可能为0 1 2 3 4 5 6 7 8 9 10这11种,分别对应的最后一位身份证的号码为1 0 X 9 8 7 6 5 4 3 2。
弄懂这个后,很快就能写出Python的计算程序了:  
1= "34052419800101001" #这个是要查的身份证号码的前17位
2 
3#计算总和
4sum = int(s[0]) * 7 + int(s[1]) * 9 + int(s[2]) * 10 + int(s[3]) * 5 + int(s[4]) * 8 + int(s[5]) * 4 + int(s[6]) * 2 + int(s[7]) * 1 + int(s[8]) * 6 + int(s[9]) * 3 + int(s[10]) * 7 + int(s[11]) * 9 + int(s[12]) * 10 + int(s[13]) * 5 + int(s[14]) * 8 + int(s[15]) * 4 + int(s[16]) * 2
5 
6#输出校验码
7print '10X98765432'[sum % 11]

有没有觉得计算总和非常无语,下面来简化代码:  
01= "34052419800101001"
02 
03#分组
04temp = zip(s[0:17], [7910584216379105842])
05print temp
06 
07#相乘
08temp2 = map(lambda x:int(x[0])*x[1], temp)
09print temp2
10 
11#相加
12temp3 = sum(temp2)
13#或者这样写:
14#temp3 = reduce(lambda x, y : x + y, temp2)
15print temp3
16 
17#最终结果
18print '10X98765432'[temp3 % 11]
19 
20#写成一行代码就是这样
21print '10X98765432'[sum(map(lambda x: int(x[0]) * x[1], zip(s[0:17], [7910584216379105842]) )) % 11]
22#print '10X98765432'[reduce(lambda x, y: x + y, map(lambda x: int(x[0]) * x[1], zip(s[0:17], [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]) )) % 11]

可能不熟悉Python的还看不懂怎么zip、map和reduce的作用,我再解释下吧。(sum太简单了,就不说了,相当于reduce的简化版。) 

zip是迭代各个参数,并返回一个元组的列表。第i个元组由参数的第i个元素组成。当一个参数迭代完成后,就结束zip,其余参数未迭代的部分忽略。 
举例来说:  
01>>> a = [123]
02>>> b = [456]
03>>> zip(a, b)
04[(14), (25), (36)]
05>>> zip([12], *[(34), (56)]) #星号(*)是把列表的元素转换为参数 [(1, 3, 5), (2, 4, 6)]
06>>> zip(*zip(a, b)) #相当于unzip [(1, 2, 3), (4, 5, 6)]
07>>> (x, y) = zip(*zip(a, b))
08>>> x
09(123)
10>>> y
11(456)
12>>> c = [78910]
13>>> zip(a, c)
14[(17), (28), (39)]
15>>> zip(a, b, c)
16[(147), (258), (369)]
17>>> d = 'abcd' >>> zip(c, d)
18[(7'a'), (8'b'), (9'c'), (10'd')]

map则是将一个函数迭代处理各个参数,返回结果列表。与zip不同的是,如果有个参数比较短,迭代完它后将用None来代替不足的元素,如果None不支持该操作,可能会抛出异常。 
演示:  
01>>> map(lambda x: 2 * x, [123])
02[246]
03>>> map(lambda x: x[0+ x[1], [(14), (25), (36)])
04[579]
05>>> map(lambda x, y: x + y, [123], [456])
06[579]
07>>> map(lambda x, y: x + y, [123], [4567])
08Traceback (most recent call last):
09  File "<stdin>", line 1in <module>
10  File "<stdin>", line 1in <lambda>
11TypeError: unsupported operand type(s) for +'NoneType' and 'int' #最后的None + 7会出错

reduce是用一个函数从左至右依次迭代处理各个元素,并返回最后的总结果。此外,如果有第3个参数的话,会将第3个参数当成初始值。  
01>>> reduce(lambda x, y: x + y, [12345]) #计算((((1+2)+3)+4)+5)
0215
03>>> reduce(lambda x, y: x + y, range(101)) #从1加到100
045050
05>>> reduce(lambda x, y: x * y, range(111)) #计算10的阶乘
063628800
07>>> print reduce(lambda x, y: str(x) + str(y), range(11), '输出1~10: ')
08输出1~10012345678910
09>>> print reduce(lambda x, y: (x + '%d'% y, range(11), '输出0~10: ')
10输出0~10012345678910
11>>> print (lambda n, m: reduce(lambda x, y: x + ** y, xrange(m + 1)))(34#计算n+n^2+n^3....n^m,n和m我给了4
12120
13>>> (lambda n: reduce(lambda x, y: x * y, xrange(1, n + 1)))(10# 计算10的阶乘(虽然我没优化算法,但计算10000的阶乘也不用1秒)
143628800

Python果然是非常方便的东西啊~ 

========== 我是分割线 ============= 
PS:原文的 URL 中带中文,在原文链接中无法给全,特此注明。引用自这里。 


原创粉丝点击