一种简单但非常实用的校验算法--卢恩算法(Luhn)

920 阅读3分钟

简介

卢恩算法(Luhn Algorithm),也称为模10算法(Mod 10 Algorithm),是由IBM科学家Hans Peter Luhn在1954年提出的一种简单校验和算法,主要用于验证各种数字标识符的有效性,如:

  1. 信用卡号(Visa、MasterCard、American Express等)
  2. IMEI(国际移动设备识别码),例如我的IMEI是867238058873512
  3. SIM卡的唯一标识ICCID
  4. 注意:身份证最后一位并不是卢恩校验,但也是用了类似的校验算法,后续再单独介绍。

算法原理

卢恩算法的核心思想是通过对数字进行加权计算,并检查最终结果是否能被10整除,从而判断数字是否有效。

计算步骤

1.从右到左,对每隔一位乘以2(从最右边的第二个数字开始乘以2); 2.如果乘以2后的数字大于9,则减去9(或拆分成个位+十位相加); 3.将所有数字相加,得到总和; 4.检查总和是否能被10整除:

如果 总和 % 10 == 0,则该数字有效。 否则,该数字无效。

示例

假设我们要验证信用卡号 7992 7398 713(最后一位是校验位): 步骤1:从右到左,每隔一位乘以2

原始数字79927398713
位置1110987654321
计算方式×1×2×1×2×1×2×1×2×1×2×1
计算后7189476916723

步骤2:处理大于9的数字(拆分成个位+十位) 18 → 1 + 8 = 9 16 → 1 + 6 = 7 更新后的数字: | 数字 | 7 | 9 | 9 | 4 | 7 | 6 | 9 | 7 | 7 | 2 | 3 |

步骤3:计算总和 7 + 9 + 9 + 4 + 7 + 6 + 9 + 7 + 7 + 2 + 3 = 70

步骤4:检查是否能被10整除 70 % 10 == 0 → 有效

代码实现

Python 实现


def luhn_checksum(card_number):
    digits = [int(d) for d in str(card_number)]
    odd_digits = digits[-1::-2]  # 从右到左的奇数位(第1、3、5...位)
    even_digits = digits[-2::-2]  # 从右到左的偶数位(第2、4、6...位)
    
    checksum = sum(odd_digits)
    for d in even_digits:
        checksum += sum(divmod(d * 2, 10))  # 如果d*2>=10,则拆分成1+(d*2-10)
    
    return checksum % 10 == 0

# 示例
card_number = "79927398713"
print(luhn_checksum(card_number))  # True

给出一串数字,计算其卢恩位:


def calculate_luhn_check_digit(number_str):
    total = 0
    # 从右往左处理每一位(不包括校验位)
    for i, ch in enumerate(reversed(number_str)):
        digit = int(ch)
        # 偶数位(从0开始计数)需要×2
        if i % 2 == 0:
            digit *= 2
            if digit > 9:
                digit -= 9
        total += digit
    return (10 - (total % 10)) % 10

# 示例
number = "7992739871"
check_digit = calculate_luhn_check_digit(number)
print(f"校验位是: {check_digit}")  # 输出3
print(f"完整号码: {number}{check_digit}")  # 输出79927398713

总结

  1. 计算时是从右往左数(校验位是第1位,它左边的是第2位)
  2. 最终校验位要使总和能被10整除
  3. 模10操作确保当总和已经是10的倍数时,校验位为0

在线卢恩算法计算器

本人在个人网站开发了一个在线的卢恩校验计算器,有兴趣可以试试。 在线卢恩校验计算器