safer isbn normalization

This commit is contained in:
Mouse Reeve 2020-10-30 12:57:31 -07:00
parent 3fc1f46897
commit 3ca50a7573

View file

@ -1,4 +1,6 @@
''' database schema for books and shelves ''' ''' database schema for books and shelves '''
import re
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.http import http_date from django.utils.http import http_date
@ -186,15 +188,18 @@ class Edition(Book):
def isbn_10_to_13(isbn_10): def isbn_10_to_13(isbn_10):
''' convert an isbn 10 into an isbn 13 ''' ''' convert an isbn 10 into an isbn 13 '''
isbn_10 = isbn_10.replace('-', '') isbn_10 = re.sub(r'[^0-9X]', '', isbn_10)
# drop the last character of the isbn 10 number (the original checkdigit) # drop the last character of the isbn 10 number (the original checkdigit)
converted = isbn_10[:9] converted = isbn_10[:9]
# add "978" to the front # add "978" to the front
converted = '978' + converted converted = '978' + converted
# add a check digit to the end # add a check digit to the end
# multiply the odd digits by 1 and the even digits by 3 and sum them # multiply the odd digits by 1 and the even digits by 3 and sum them
try:
checksum = sum(int(i) for i in converted[::2]) + \ checksum = sum(int(i) for i in converted[::2]) + \
sum(int(i) * 3 for i in converted[1::2]) sum(int(i) * 3 for i in converted[1::2])
except ValueError:
return None
# add the checksum mod 10 to the end # add the checksum mod 10 to the end
checkdigit = checksum % 10 checkdigit = checksum % 10
if checkdigit != 0: if checkdigit != 0:
@ -207,13 +212,16 @@ def isbn_13_to_10(isbn_13):
if isbn_13[:3] != '978': if isbn_13[:3] != '978':
return None return None
isbn_13 = isbn_13.replace('-', '') isbn_13 = re.sub(r'[^0-9X]', '', isbn_13)
# remove '978' and old checkdigit # remove '978' and old checkdigit
converted = isbn_13[3:-1] converted = isbn_13[3:-1]
# calculate checkdigit # calculate checkdigit
# multiple each digit by 10,9,8.. successively and sum them # multiple each digit by 10,9,8.. successively and sum them
try:
checksum = sum(int(d) * (10 - idx) for (idx, d) in enumerate(converted)) checksum = sum(int(d) * (10 - idx) for (idx, d) in enumerate(converted))
except ValueError:
return None
checkdigit = checksum % 11 checkdigit = checksum % 11
checkdigit = 11 - checkdigit checkdigit = 11 - checkdigit
if checkdigit == 10: if checkdigit == 10: