Merge pull request #257 from mouse-reeve/isbn

safer isbn normalization
This commit is contained in:
Mouse Reeve 2020-10-30 12:59:10 -07:00 committed by GitHub
commit 6661cd3fa6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 2 deletions

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,14 +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 = 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
checksum = sum(int(i) for i in converted[::2]) + \ try:
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:
@ -206,11 +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 = 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
checksum = sum(int(d) * (10 - idx) for (idx, d) in enumerate(converted)) try:
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:

View file

@ -54,11 +54,21 @@ class Book(TestCase):
isbn_13 = isbn_10_to_13(isbn_10) isbn_13 = isbn_10_to_13(isbn_10)
self.assertEqual(isbn_13, '9781788161671') self.assertEqual(isbn_13, '9781788161671')
isbn_10 = '1-788-16167-X'
isbn_13 = isbn_10_to_13(isbn_10)
self.assertEqual(isbn_13, '9781788161671')
def test_isbn_13_to_10(self): def test_isbn_13_to_10(self):
isbn_13 = '9781788161671' isbn_13 = '9781788161671'
isbn_10 = isbn_13_to_10(isbn_13) isbn_10 = isbn_13_to_10(isbn_13)
self.assertEqual(isbn_10, '178816167X') self.assertEqual(isbn_10, '178816167X')
isbn_13 = '978-1788-16167-1'
isbn_10 = isbn_13_to_10(isbn_13)
self.assertEqual(isbn_10, '178816167X')
class Shelf(TestCase): class Shelf(TestCase):
def setUp(self): def setUp(self):