Reputation: 55
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
Upvotes: 0
Views: 4251
Reputation: 176
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.
Upvotes: 0
Reputation: 177481
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
Upvotes: 0
Reputation: 87064
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.
Upvotes: 2
Reputation: 1235
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).
Upvotes: 1