0

I need to write a function that validates a 13 digit ISBN. It needs to start with 978 or 979, end with a single digit, and the remaining sections need to be at least 1 digit in length. I need some help to make this work, I don't understand why it never returns true

def validate(s)
 lst = s.split("-")
 isbn= False
 if lst[0] == "978" or lst[0] == "979":
     if len(lst[1])>=1 and len(lst[2])>=1:
         if len(lst[3])==1:
            isbn= True
return isbn
Pang
  • 9,564
  • 146
  • 81
  • 122
Miryloth
  • 55
  • 1
  • 2
  • 9
  • 1
    Please provide a sample input on which it fails. – UltraInstinct Jun 29 '16 at 23:29
  • 978-3-16-148410-0 would pass, 978-3-16-148410 would fail – Miryloth Jun 29 '16 at 23:57
  • Possible duplicate of [How to use Python to find all isbn in a text file?](http://stackoverflow.com/questions/14258720/how-to-use-python-to-find-all-isbn-in-a-text-file) – PyNEwbie Jun 30 '16 at 00:02
  • Error 1: Missing a colon at end of the 'def' statement. Error 2: The 'return isbn' statement is not indented to put it inside the function. – clp2 Jun 30 '16 at 00:04

4 Answers4

2

ISBN-13 requires 13 digits to be valid. Your code does not check that all characters are digits (excluding the - separator), nor does it check the actual length. Also, five parts are required, and you could be verifying the check digit.

Specifically your code fails to ever return True because the fourth segment (lst[3]) checks for exactly one character (if len(lst[3])==1:), however, that element will typically be longer than 1 digit.

There are python libraries available via PyPI that can validate ISBN codes. Here's an example using isbnlib:

>>> import isbnlib
>>> isbnlib.is_isbn13('978-3-16-148410-0')
True
>>> isbnlib.is_isbn13('978-3-16-148410-5')
False
>>> isbnlib.is_isbn13('978-3-16-148410-A')
False
>>> isbnlib.is_isbn13('979-3-16-148410-9')
True

Another, lighter weight library is pyisbn:

>>> import pysisbn
>>> pyisbn.validate('979-3-16-148410-9')
True
>>> pyisbn.validate('979-3-16-148410-0')
False

The advantage of using these libraries, other than saving you the hassle of parsing ISBN strings yourself, is that they offer additional functionality such as converting from ISBN-13 to ISBN-10.

mhawke
  • 84,695
  • 9
  • 117
  • 138
1

You should use regular expression and this is exactly why it is used for:

>>> import re
>>> def validate(isbn):
        isbn_regex = re.compile('^(978|979)-\d+-\d+-\d$')
        return isbn_regex.search(isbn) is not None

>>> print validate('978-12-12-2')
    True

Note: This works as per your logic in the above code(except for you didn't check whether it's a digit).

Devi Prasad Khatua
  • 1,185
  • 3
  • 11
  • 23
  • Oddly, this regex will not work for any real ISBN-13 codes, only for those following the OP's invalid format :) @Miryloth: you need to adapt the regex pattern provided in this answer to work with real ISBN-13 codes, e.g. ` ^97(8|9)(-\d+){4}$`. Finally, you should verify the check digit. – mhawke Jun 30 '16 at 22:37
  • Yes the reason why I said it works exactly as Ops logic! – Devi Prasad Khatua Jul 01 '16 at 02:40
0

An ISBN-13 consists of five groups of numbers and the last digit is a check digit. Here's a function to make sure there are five groups, exactly 13 digits, and validates the check digit. It works with your samples:

import re

def validate(s):
    d = re.findall(r'\d',s)
    if len(d) != 13:
        return False
    if not re.match(r'97[89](?:-\d+){3}-\d$',s):
        return False

    # The ISBN-13 check digit, which is the last digit of the ISBN, must range from 0 to 9
    # and must be such that the sum of all the thirteen digits, each multiplied by its
    # (integer) weight, alternating between 1 and 3, is a multiple of 10.
    odd = [int(x) for x in d[::2]]
    even = [int(x)*3 for x in d[1::2]]
    return (sum(odd)+sum(even)) % 10 == 0

trials = '''\
978-3-16-148410-0
978-3-16-148410
978-0-306-40615-7
978-0306-40615-7
979-11111-11-11-2
978-7654-321-12-4
977-7654-321-12-4
978-7654-321-1-41
978-7654-321-1-4
978-7654-321-122-4
'''.splitlines()

for trial in trials:
    print(validate(trial),trial)

Output:

True 978-3-16-148410-0
False 978-3-16-148410        # too few numbers and groups       
True 978-0-306-40615-7
False 978-0306-40615-7       # too few groups
True 979-11111-11-11-2
False 978-7654-321-12-4      # wrong check digit
False 977-7654-321-12-4      # didn't start with 978 or 979
False 978-7654-321-1-41      # didn't end in one digit.
False 978-7654-321-1-4       # too few digits
False 978-7654-321-122-4     # too many digits
Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
0

Error 1: Missing a colon at end of the 'def' statement.

Error 2: The 'return isbn' statement is not indented; it is outside the function but should be inside.

Error 3: The line checking the length of lst[3] does not check the last element of the isbn string when there are more than four elements in lst.

The split command creates five elements in lst for your first string, 978-3-16-148410-0; but lst[3] has 6 digits, and the length test fails.

The split command creates four elements in lst for your second string, 978-3-16-148410; but lst[3] has 6 digits, and the length test fails.

Consider using lst[-1] to specify the last element of lst, regardless of how many elements it contains. If your i/p is formatted correctly, the o/p should be correct.

clp2
  • 176
  • 2
  • 6