Python实例—计算ISBN的校验和并返回ISBN号

咳咳,科普一下,ISBN的中文名为国际标准书号,简单来说就是一本书的身份证,经常和条形码在一起使用。

Python原版书 python isbn_Python原版书


话不多说,我们直接进入正题:

一、题目要求与分析

  国际标准书号用10为数字唯一标识一本书(哈哈,莫说我骗你噻,自从2007年1月1日起,实行新版ISBN,即在原来的10位数字前加上3位图书产品代码“978”,称为欧洲商品编号,总之就是方便检索的,这段很尴尬,隐了隐了),最右边的数字为校验和,可由其他9位数字计算出来,且d1 + 2d2 + 3d3 + …+ 10d10 必须是11的倍数。校验和必须是介于0到10中的一个数字,用X标识10。例如:020131452的校验和是5,因为对于下边11倍数的公式,5是唯一的介于0到10之间的数:

Python原版书 python isbn_整除_02


要求任意给出前9位数字,需要计算校验和并返回ISBN号。

Python原版书 python isbn_python_03


好吧,不得不说我在构建这个数学公式上耗费了大半元气。

  题目分析:上边啰嗦了那么多,终归是一个找数字的问题,只是这个数字比较复杂,既满足在0-10之间,又满足和其他数相加是11的倍数。如果这个数找到了,那么什么输出ISBN号通通不在话下,我们将问题简化可以分解成以下三步:

   步骤1: 限定校验和k(就是那个数,我们也专业点儿)的范围为0-10

   步骤2: 计算其他数(就是那个 2d2 + 3d3 + …+ 10d10),这里用number_other表示;

   步骤3: 限定倍数(就是相加是11的倍数那个倍数),这里用mul表示.

注意:我为什么要限定倍数nul 呢?

   这个问题是这道题的核心,这里我不妨谈谈自己的思路,题中提到11的倍数,但又没有说这个倍数具体是多少,所以我只能用一个变量mul来代替,让它从0往后遍历就好了,但是新的问题出现了;这么一直遍历下去也不是办法,毕竟刹不住车不行呀。

   所以这里的问题又转化成了找最大倍数的问题,怎么找最大倍数呢?不妨看一下这个公式:

Python原版书 python isbn_整除_04


这样就一目了然了,对吧!k增大mul增大,所以很容易求出来mul的最大值是45,如果mul超出这个值,则k就不能落在0-10之间了。

讲到这里,想必后边的代码过程大家都势如破竹了,接下来我们把代码给码列一下……

Python原版书 python isbn_Python原版书_05


二、源代码部分

def ISBN(n):
    number = str(n)
    number_other = 0
    j = 2
    for i in range(-1,-10,-1): 
           number_other +=  eval(number[i]) * j
           j += 1
    for mul in range(0,45):       #找m可能取到的最大值
        for k in range(0,11):
            if (number_other + k) / 11 == mul:        #我滴天,千万不能用整除
                if 0 <= k <=9:
                    d = str(k)
                if k == 10:
                    d = "x"
                trueISBN = number + d

    return (trueISBN)


for num in [201314525, 488888913, 977889994, 753231846, 701134069]:
    trueISBN = ISBN(num)
    print(trueISBN)

嗯,中规中矩的代码,不掺任何浮躁华丽……

三、结构分析

(1) 制造一个函数模块

  害,这种类型的难题不编写一个函数总觉得对不起自己,一方面是为了养成一个好的习惯,毕竟模块化处理嘛,方便以后干惊天动地的事,另一方面也看起来舒心,简洁整齐,有条不紊,多像正规军。

Python原版书 python isbn_python_06


  注意:函数的参数一定要传递正确,要不然浪过头就不好了。

(2) 计算num_other

  num_other也不是不好算,只是大家有没有发现那个公式里数字的计算方式是倒着的,比如020131452(图也给你了,快看看),所以你要么倒着让它每个数进行乘法运算,要么就是让他每个数乘以一个倒着增长的数。

Python原版书 python isbn_python_07


我这里选择了前者,这里涉及字符串的索引问题,你要是不懂的话可以看看我的“Python字符串的索引”

于是乎,产生了如下一段代码:

number = str(n)
    number_other = 0
    j = 2
    for i in range(-1,-10,-1): 
           number_other +=  eval(number[i]) * j
           j += 1

注意:j的值要从2开始,因为乘1被校验和k(文章一开始提到的那个数)占了
(3) 计算核心数字k
  通过一开始我们的分析,可以知道要进行两次限定,于是这里就用了两个for循环,第一个循环限定mul的值最大为45(为啥写46就不必说了哈,range函数的特性嘛对不对),第二次限定k的范围为0-10, 所以这个计算核心数字k的过程就悄然跃然纸上:

for mul in range(0,46):       #找m可能取到的最大值
       for k in range(0,11):
           if (number_other + k) / 11 == mul:        #我滴天,千万不能用整除
               if 0 <= k <=9:
                   d = str(k)
               if k == 10:
                   d = "x"
               trueISBN = number + d

注意:
  1 . 因为题中说“用X标识10”,所以记得加一个判断,判定k是不是10,如果是的话就用X代替;
  2 . 公式描述的那个部分千万不能用整除,“/”和“//”是有区别的,整除的话在这里会使很大一部分数都满足条件,仔细想想?
   3 . 函数的最后要写return,要不前面写的都白搭了。切记切记。

四、本次的运行结果

Python原版书 python isbn_校验和_08


那就在这里祝你好运咯~


听说,爱学习的人都特帅……

Python原版书 python isbn_整除_09