检查ISBN号是否正确

hel*_*hod 13 python

我给了一些ISBN号,例如3-528-03851(无效),3-528-16419-0(有效).我应该写一个测试ISBN号是否有效的程序.

这是'我的代码:

def check(isbn):
    check_digit = int(isbn[-1])
    match = re.search(r'(\d)-(\d{3})-(\d{5})', isbn[:-1])

    if match:
        digits = match.group(1) + match.group(2) + match.group(3)
        result = 0

        for i, digit in enumerate(digits):
          result += (i + 1) * int(digit)

        return True if (result % 11) == check_digit else False

    return False
Run Code Online (Sandbox Code Playgroud)

我使用正则表达式来检查a)格式是否有效以及b)提取ISBN字符串中的数字.虽然它似乎有用,但作为一名Python初学者,我很想知道如何改进我的代码.建议?

Gle*_*ard 17

首先,尽量避免这样的代码:

if Action():
    lots of code
    return True
return False
Run Code Online (Sandbox Code Playgroud)

翻转它,因此大部分代码不是嵌套的.这给了我们:

def check(isbn):
    check_digit = int(isbn[-1])
    match = re.search(r'(\d)-(\d{3})-(\d{5})', isbn[:-1])

    if not match:
        return False

    digits = match.group(1) + match.group(2) + match.group(3)
    result = 0

    for i, digit in enumerate(digits):
      result += (i + 1) * int(digit)

    return True if (result % 11) == check_digit else False
Run Code Online (Sandbox Code Playgroud)

代码中有一些错误:

  • 如果校验位不是整数,则会引发ValueError而不是返回False:"0-123-12345-Q".
  • 如果校验位为10("X"),则会引发ValueError而不是返回True.
  • 这假设ISBN始终分组为"1-123-12345-1".事实并非如此; ISBN是任意分组的.例如,分组"12-12345-12-1"有效.见http://www.isbn.org/standards/home/isbn/international/html/usm4.htm.
  • 这假定ISBN按连字符分组.空间也有效.
  • 它不会检查是否没有多余的字符; '0-123-4567819'返回True,忽略最后的额外1.

所以,让我们简化一下.首先,删除所有空格和连字符,并通过在'^ ... $'中支持它来确保正则表达式与整行匹配.这可以确保它拒绝太长的字符串.

def check(isbn):
    isbn = isbn.replace("-", "").replace(" ", "");
    check_digit = int(isbn[-1])
    match = re.search(r'^(\d{9})$', isbn[:-1])
    if not match:
        return False

    digits = match.group(1)

    result = 0
    for i, digit in enumerate(digits):
      result += (i + 1) * int(digit)

    return True if (result % 11) == check_digit else False
Run Code Online (Sandbox Code Playgroud)

接下来,让我们修复"X"校验位问题.匹配正则表达式中的校验位,因此正则表达式验证整个字符串,然后正确转换校验位.

def check(isbn):
    isbn = isbn.replace("-", "").replace(" ", "").upper();
    match = re.search(r'^(\d{9})(\d|X)$', isbn)
    if not match:
        return False

    digits = match.group(1)
    check_digit = 10 if match.group(2) == 'X' else int(match.group(2))

    result = 0
    for i, digit in enumerate(digits):
      result += (i + 1) * int(digit)

    return True if (result % 11) == check_digit else False
Run Code Online (Sandbox Code Playgroud)

最后,使用生成器表达式并且max是在Python中进行最终计算的更惯用的方式,并且可以简化最终条件.

def check(isbn):
    isbn = isbn.replace("-", "").replace(" ", "").upper();
    match = re.search(r'^(\d{9})(\d|X)$', isbn)
    if not match:
        return False

    digits = match.group(1)
    check_digit = 10 if match.group(2) == 'X' else int(match.group(2))

    result = sum((i + 1) * int(digit) for i, digit in enumerate(digits))
    return (result % 11) == check_digit
Run Code Online (Sandbox Code Playgroud)

  • 做得很好.我看到的唯一缺陷是允许连续的连字符或空格,它们应该被标记为错误. (3认同)