Python入门习题(54)——团体程序设计天梯赛习题:查验身份证

题目描述

题目编号:L1-016
作者: 陈越
单位: 浙江大学
时间限制: 400 ms
内存限制: 64 MB
代码长度限制: 16 KB
来源:PTA网站团体程序设计天梯赛-练习集

题目描述
一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下:

首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};然后将计算的和对11取模得到值Z;最后按照以下关系对应Z值与校验码M的值:

Z:0 1 2 3 4 5 6 7 8 9 10
M:1 0 X 9 8 7 6 5 4 3 2

现在给定一些身份证号码,请你验证校验码的有效性,并输出有问题的号码。

输入格式:
输入第一行给出正整数N(≤100)是输入的身份证号码的个数。随后N行,每行给出1个18位身份证号码。

输出格式:
按照输入的顺序每行输出1个有问题的身份证号码。这里并不检验前17位是否合理,只检查前17位是否全为数字且最后1位校验码计算准确。如果所有号码都正常,则输出All passed。

输入样例1:
4
320124198808240056
12010X198901011234
110108196711301866
37070419881216001X

输出样例1:
12010X198901011234
110108196711301866
37070419881216001X

输入样例2:
2
320124198808240056
110108196711301862

输出样例2:
All passed

解题思路

数据结构
  1. 用一个字符串id存储输入的身份证号码。在计算第18位校验码的时候,把前17位数字转换为整数。
  2. 用一个列表weights(即数组)存储权重值。第 i 个权重的下标(即索引)与身份证号码中的第 i 位相对应,i = 1, 2, …, 17。
  3. 用一个列表M_codes存储校验码(字符)。Z值等于z的话,那么M_codes[z]就是正确的校验码,也就是身份证号码第18位该出现的字符,z=0, 1, …, 10。如果输入的身份证号码id的第18位不等于该校验码,那么id中的校验码有误。
  4. 用一个列表wrong_ids存储不正确的身份证号码。如果列表长度为0,表明所有身份证号码都是正确的,输出“All passed”。
算法

一、重复执行,处理每一个身份证号码id:

  1. 检查id字符串长度是否是18位。不是的话,把id加入wrong_ids,跳转至处理下一个身份证号码。
  2. 检查id前17位是否都是数字。不是的话,把id加入wrong_ids,跳转至处理下一个身份证号码。
  3. 计算校验码M。检查id中第18位是否等于校验码M。不是的话,把id加入wrong_ids,跳转至处理下一个身份证号码。

二、如果列表wrong_ids长度为0,表明所有身份证号码都是正确的,输出“All passed”。否则输出wrong_ids列表内的元素。

细节
  1. 输入的身份证号码都是18位。
  2. 只要身份证号码的前17位是数字,就视为合法的。如果前17位有非数字字符,则是非法的。
  3. 把权重值和校验码M的值从题目描述中复制拷贝到代码中,不要手工输入——容易犯错。

参考答案

#ss是数字字符串吗
def is_digits(ss):
    for s in ss:
        if not s.isdigit():
            return False
    return True


weights = [7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2]  #权重
M_codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']  #除以11的余数对应的校验码
wrong_ids = []  #错误的身份证号码
n = int(input())
for i in range(n):
    id = input()
    if len(id) != 18:  #不足18位,身份证号码有误
        wrong_ids.append(id)
        continue

    if not is_digits(id[:17]):  #身份证号码的前17位不全是数字,有误
        wrong_ids.append(id)
        continue
	#计算验证码
    total = 0
    for j in range(17):
        total += int(id[j]) * weights[j]

    z = total % 11
    if M_codes[z] != id[17]:  #第18位验证码不正确
        wrong_ids.append(id)

if len(wrong_ids) == 0:
    print("All passed")
else:
    for id in wrong_ids:
        print(id)

测试用例

  1. 题目描述给出的第一组测试用例覆盖了身份证号码有误的情形;覆盖了前17位不合法的情形。

  2. 题目描述给出的第二组测试用例覆盖了全部身份证号码正确的情形。最后的校验码是2,6。

  3. 校验码分别是1, 0, X, 9, 8, 7, 6, 5 ,4, 3, 2的情形。如果校验码M的值从题目描述中复制拷贝到代码中,这一测试用例可以省略。下面的测试用例是在题目描述给出的第二组测试用例的基础上稍加改造得到的。
    样例输入
    11
    320124138808240051
    320124148808240050
    32012415880824005X
    320124168808240059
    320124178808240058
    320124188808240057
    320124198808240056
    321124108808240055
    321124118808240054
    321124128808240053
    321124138808240052
    样例输出
    All passed

  4. 如果权重值从题目描述中复制拷贝到代码中,就不会发生错误,无需为它设计测试用例。

小结

  1. 本题难度不大。在PTA网站上,通过率是31%,不高,所以在此发文讲解。
  2. 抽取is_digits函数是必要的。不信的话,你尝试编写不使用is_digits函数的代码看看,有可能你将被两重循环绕晕。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值