Luhn算法与信用卡识别完善《python语言程序设计》2018版--第8章14题利用字符串输入作为一个信用卡号之三

前言

12月3日的文章里,我们设计了isValid [1](#1)

一、题面(文字版)

(金融:信用卡号合法性)使用"字符串"输入作为一个信用卡号来改写编程题6.29

二、题面里的函数

python 复制代码
# Return true if the card number is valid
def isValid(number):

# Get the result from Step 2
def sumOfDoubleEvenPlace(number):

# Return this number if it is a single digit, otherwise, return
# the sum of the two digits
def getDigit(number):

# Return sum of odd place digits in number
def sumOfOddPlace(number):

# Return true, if the digit d is a prefix for number
def perfixMatched(number,d):

# Return the number of digits in d
def getSize(d):

# Return the first k number of digits from number. If the
# number of digits in number is less than k, return number.
def getPerfix(number,k)

三、Luhn运算流程图

四、def sumOfDoubleEvenPlace(number):偶数求和

python 复制代码
def sumOfDoubleEvenPlace(number): #对偶数进行乘2,然后累加
    lenNum = len(number) #量出字符串长度
    for i in range(1,lenNum,2): #按隔一个进行一次的原则取偶数
        print(number[-i],end=" ") #先打印看一下是否是偶数

4.1 我们做累加设计

4.1.1 print好还是return好呢??

python 复制代码
def sumOfDoubleEvenPlace(number):
    lenNum = len(number)
    mulNum = 0
    for i in range(1, lenNum, 2):
        mulNum += int(number[-i])
        return mulNum
sumNum =sumOfDoubleEvenPlace(a)
print(sumNum)
print(type(sumNum))

这个和我们之前的print好还是return好一个情况,打印是遍历一遍所有的偶数,可是return有一个结果就停了 [2](#2) [3](#3)

4.1.2 将return的缩进提前

python 复制代码
def sumOfDoubleEvenPlace(number):
    lenNum = len(number)
    mulNum = 0
    for i in range(1, lenNum, 2):
        mulNum += int(number[-i])
    return mulNum

a = "4388576018402626"
sumNum =sumOfDoubleEvenPlace(a)
print(f"{a} 偶数位相加等于",sumNum)
print("sumNum函数输出的类型",type(sumNum))

五、sumOfOddPace(number)奇数求和

5.1初期代码

python 复制代码
def sumOfOddPace(number):
    lenNum = len(number)#计算字符串长度
    mulNum = 0
    print(f"倒序显示字符串{number}的奇数位,如下: ")
    for i in range(2, lenNum+2, 2):
        if 2 * int(number[-i]) > 9:#如果相乘结果大于9就进行相加
            mulNum=2*int(number[-i])#相乘结果存储器
            a = str(mulNum) #将变量字符串话进行提取
            print(int(a[0]) + int(a[1])) #将提取后的两个字符再次变回int进行相加

5.2简单累积

python 复制代码
def sumOfOddPace(number):
    lenNum = len(number)#计算字符串长度
    mulNum = 0
    mulNumThanNine = 0 #存储相乘结果大于9的累加变量
    mulNumTotal = 0 #存储相乘小于9的累加变量
    print(f"倒序显示字符串{number}的奇数位,如下: ")
    for i in range(2, lenNum+2, 2):
        if 2 * int(number[-i]) > 9:#如果相乘结果大于9就进行相加
            mulNum = 2 * int(number[-i])#相乘结果存储器
            a = str(mulNum) #将变量字符串话进行提取
            mulNumThanNine +=int(a[0]) + int(a[1]) #将提取后的两个字符再次变回int进行相加
        else:#如果相乘结果小于2
            mulNumTotal += 2 * int(number[-i]) 
        
    return mulNumThanNine + mulNumTotal #将两种结果进行相加
a = "4388576018402626"
print("对奇数进行相乘和相加最后得到的结果",sumOfOddPace(a))
print("结果的type为整数",type(sumOfOddPace(a)))

六、奇数偶数求和并且进行整除判断

python 复制代码
 识别银行卡
def isValid(number):
    lenNum = len(number)  # 识别银行卡字符串长度
    if 13 <= lenNum <= 16:  # 如果银行卡长度在13到16之间就识别属于什么类银行卡
        if number[0] == "4" and getResult(number) is True:  # 如果头一个字符是4则是visa卡
            print(f"银行卡{number}是Visa卡")
        elif number[0] == "5" and getResult(number) is True:
            print(f"银行卡{number}是Master卡")
        elif number[:2] == "37" and getResult(number) is True:
            print(f"银行卡{number}是American Express卡")
        elif number[0] == "6" and getResult(number) is True:
            print(f"银行卡{number}是Discover卡")
        else:  # 如果不符合则显示磁卡
            print(f"{number},此卡无法识别,请您提供该卡类型给管理员")
    else:
        print(f"{number}不是银行卡,请您重新输入,或联系管理员")


def sumOfDoubleEvenPlace(number):
    lenNum = len(number)
    mulNum = 0
    for i in range(1, lenNum, 2):
        mulNum += int(number[-i])
    return mulNum

def sumOfOddPace(number):
    lenNum = len(number)#计算字符串长度
    mulNum = 0
    mulNumThanNine = 0 #存储相乘结果大于9的累加变量
    mulNumTotal = 0 #存储相乘小于9的累加变量
    for i in range(2, lenNum+2, 2):
        if 2 * int(number[-i]) > 9:#如果相乘结果大于9就进行相加
            mulNum = 2 * int(number[-i])#相乘结果存储器
            a = str(mulNum) #将变量字符串话进行提取
            mulNumThanNine +=int(a[0]) + int(a[1]) #将提取后的两个字符再次变回int进行相加
        else:#如果相乘结果小于2
            mulNumTotal += 2 * int(number[-i]) 
        
    return mulNumThanNine + mulNumTotal #将两种结果进行相加
def getResult(number):
    sumTotal = sumOfDoubleEvenPlace(number) + sumOfOddPace(number) #奇数偶数结果相加
    if sumTotal % 10 == 0: #对结果进行整除,能除尽为合格卡号
        print("用户输入的此银行卡号是有效")
        return True
    else:
        print("用户输入的此银行卡号不是有效格式,请检查后重新输入")
        return False
            
def main():
    a = isValid("4388576018402626")
    b = isValid("438852601840707")  # visa卡
    c = isValid("5388576018402626")  # Master卡
    d = isValid("3788576018402626")  # American Express卡
    e = isValid("6388576018402626")  # Discover卡

main()

IndexError:string index out of range

不对呀。sumOfOddPace(number):之前是好使的。大家可以看第四节,怎么到这里就不好使了呢?

没有加入到isValid的sumOfOddPace是可用的呀?

问题

当卡号长度为奇数(比如438852601840707是 15 位),lenNum+2会导致i超出字符串索引范围:

例:15 位卡号lenNum=15,循环range(2,17,2)会生成2,4,6,8,10,12,14,16,当i=16时,number[-16]超出 15 位字符串的索引范围(15 位字符串倒数索引最大是 - 15),所以直接报IndexError: string index out of range

解决

吸取了教训我之前在面对偶数位卡号时写的是for i in range(2, lenNum+2, 2):,其实循环范围改为:从2开始,到lenNum+1(而非lenNum+2),步幅2

七 最终解决代码

python 复制代码
# 识别银行卡
def isValid(number):
    lenNum = len(number)  # 识别银行卡字符串长度
    if 13 <= lenNum <= 16:  # 如果银行卡长度在13到16之间就识别属于什么类银行卡
        if number[0] == "4" and getResult(number) is True:  # 如果头一个字符是4则是visa卡
            print(f"银行卡{number}是Visa卡")
        elif number[0] == "5" and getResult(number) is True:
            print(f"银行卡{number}是Master卡")
        elif number[:2] == "37" and getResult(number) is True:
            print(f"银行卡{number}是American Express卡")
        elif number[0] == "6" and getResult(number) is True:
            print(f"银行卡{number}是Discover卡")
        else:  # 如果不符合则显示磁卡
            print(f"{number},此卡无法识别,请您提供该卡类型给管理员")
    else:
        print(f"{number}不是银行卡,请您重新输入,或联系管理员")


def sumOfDoubleEvenPlace(number):
    lenNum = len(number)
    mulNum = 0
    for i in range(1, lenNum, 2):
        mulNum += int(number[-i])
    return mulNum

def sumOfOddPlace(number):
    lenNum = len(number)#计算字符串长度
    mulNumThanNine = 0 #存储相乘结果大于9的累加变量
    mulNumTotal = 0 #存储相乘小于9的累加变量
    for i in range(2, lenNum+1, 2):
        if 2 * int(number[-i]) > 9:#如果相乘结果大于9就进行相加
            mulNum = 2 * int(number[-i])#相乘结果存储器
            a = str(mulNum) #将变量字符串话进行提取
            mulNumThanNine +=int(a[0]) + int(a[1]) #将提取后的两个字符再次变回int进行相加
        else:#如果相乘结果小于2
            mulNumTotal += 2 * int(number[-i]) 
        
    return mulNumThanNine + mulNumTotal #将两种结果进行相加
def getResult(number):
    sumTotal = sumOfDoubleEvenPlace(number) + sumOfOddPlace(number) #奇数偶数结果相加
    if sumTotal % 10 == 0: #对结果进行整除,能除尽为合格卡号
        print("用户输入的此银行卡号是有效")
        return True
    else:
        print("用户输入的此银行卡号不是有效格式,请检查后重新输入")
        return False
            
def main():
    a = isValid("4388576018402626")# 非visa卡
    b = isValid("438852601840707")  # 非visa卡
    c = isValid("5388576018402626")  # 非Master卡
    d = isValid("3788576018402626")  # 非American Express卡
    e = isValid("6388576018402626")  # Discover卡

main()

八 小技巧简化版奇数位求和

将sumOfOddPlace的"翻倍后两位数相加" 简化为 "减 9"

(比如 12→1+2=3=12-9,16→1+6=7=16-9),

翻倍后若为两位数,直接减 9 等价于 "各位相加"(如 12-9=3,16-9=7),代码中可直接用doubled - 9,无需判断位数。

python 复制代码
def sumOfOddPlace(number):  # 修正函数名拼写
    lenNum = len(number)
    mulNumThanNine = 0
    mulNumTotal = 0
    # 循环范围改为:从2开始,到lenNum+1(而非lenNum+2),步幅2
    for i in range(2, lenNum+1, 2):
        digit = int(number[-i])  # 取倒数第i位(奇数位,需要翻倍)
        doubled = digit * 2
        if doubled > 9:
            # 简化:两位数相加 = 减9(比如12→3=12-9,16→7=16-9)
            mulNumThanNine += doubled - 9
        else:
            mulNumTotal += doubled
    return mulNumThanNine + mulNumTotal

"你还遇到过哪些字符串索引的坑?评论区聊聊~"


  1. 2025年12月3日在csdn中发布的文章《不含Luhn算法《python语言程序设计》2018版--第8章14题利用字符串输入作为一个信用卡号之二(识别卡号有效)》 ↩︎

  2. 参考2025年11月28日《print好还是return好`--第8章12题(生物信息:找出基因)中的问题》 ↩︎

  3. 参考2025年11月22日《《python语言程序设计》2018版--第8章12题(生物信息:找出基因)输入基因组,识别基因组和非基因组,(之最终篇)》 ↩︎

相关推荐
漏洞文库-Web安全1 小时前
CTFHub-RCE漏洞wp
android·安全·web安全·网络安全·ctf·ctfhub
月光技术杂谈1 小时前
基于Python+Selenium的淘宝商品信息智能采集实践:从浏览器控制到反爬应对
爬虫·python·selenium·自动化·web·电商·淘宝
bbq粉刷匠1 小时前
力扣-电话号码组合
java·算法
HsuHeinrich1 小时前
利用表格探索宜居城市
python·数据可视化
享哥。1 小时前
MVI 模式及mvp,mvvm对比
android
过尽漉雪千山1 小时前
Anaconda的虚拟环境下使用清华源镜像安装Pytorch
人工智能·pytorch·python·深度学习·机器学习
碧海银沙音频科技研究院1 小时前
CLIP(对比语言-图像预训练)在长尾图像分类应用
python·深度学习·分类
Dxxyyyy1 小时前
零基础学JAVA--Day41(IO文件流+IO流原理+InputStream+OutputStream)
java·开发语言·python
狗头实习生1 小时前
电话号码字母组合
java·算法·leetcode