ISBN 从12位转换为13位

1 投票
2 回答
600 浏览
提问于 2025-04-18 10:39

我正在尝试从一个12位的ISBN中计算出ISBN-13的校验位,但遇到了一个奇怪的错误。

我的12位ISBN是:978311020318

每个数字交替乘以1或3。

计算方式是这样的:9乘以1,加上7乘以3,加上8乘以1,加上3乘以3,加上1乘以1,加上1乘以3,加上0乘以1,加上2乘以3,加上0乘以1,加上3乘以3,加上1乘以1,加上8乘以3,结果是91。

然后用91除以10,得到的余数是1。

再用10减去1,结果是9,这就是我们的ISBN-13校验位。

这是我目前的代码...

def isbn_check_digit(isbn):
    s = 0
    for i, d in enumerate(isbn):
        if i % 2 == 0:
            s += int(d*1)
        else:
            s += int(d*3)
            print(s)
    return (10 - (s % 10))

print(isbn_check_digit("978311020318"))

运行后输出了以下内容...

786
1127
1239
1461
1794
2683
7

我把代码拆开来看看发生了什么。

    if i % 2 == 0:
        s += int(d*1)
        print(s)
    else:
        s += 0

9
17
18
18
18
19
1

乘以1的部分运行得很好,但为什么乘以3的部分会出现奇怪的情况呢?

2 个回答

0

@dustwuff 给出了问题的原因,但另一个解决办法是使用 map,然后把你的字符串转换成一个列表:

from itertools import izip_longest

def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)

def isbn_check_digit(isbn):
    number = list(map(int, isbn))
    check_sum = 0
    for i, d in grouper(2, number):
        check_sum += i*1 + d*3
    return 10 - check_sum % 10

map 会对可迭代的每一个元素应用一个函数。在这个例子中,使用 int 函数可以把你的字符串转换成一个数字列表。

2

因为在计算表达式 int(d * 3) 的时候,d 不是一个数字,而是一个由一个字符组成的字符串,这个字符是一个数字。所以,当你把它“乘”以3时,实际上是把这个字符重复三次:比如说,3 会变成 333,而不是 9

你需要先把字符串转换成整数,然后再乘以3:

int(d) * 3

撰写回答