Search code examples
algorithmbarcodeisbn

How to decode a barcode into ISBN?


For this question with illustrative purpose I will write Javascript code, but that's just an illustration, the question is language-agnostic.

I need to write a function which takes a barcode text (not the image) as an input and returns the ISBN as output. ISBN can be of 10 digits (older books) or 13 digits (newer books). We also know that the last digit of an ISBN is a checksum, which is computed differently if the ISBN is 10 digits long and differently if the ISBN is 13 digits long.

Assuming that input is a string, we can validate whether it is a valid ISBN, like:

function isValidISBN10(input) {
    if (input.length !== 10) return false;
    var sum = 0;
    var p = 10;
    for (var index = 0; index < 10; index++) {
        sum += ((input[index] === 'X') ? 10 : input[index]) * (p--);
    }
    return sum % 11 === 0;
}

and ISBN13 can be validated like:

function isValidISBN13(input) {
    if (input.length !== 13) return false;
    var sum = 0;
    var p = 3;
    for (var index = 0; index < 13; index++) {
        sum += input[index] * (p = (p + 2) % 4);
    }
    return sum % 10 === 0;
}

Checking a valid ISBN is:

function isValidISBN(input) {
    return isValidISBN10(input) || isValidISBN13(input);
}

As we can see, the last digit of an ISBN is the number we should add in order to make sure the result is divisible by 11 (in the case of ISBN10) and 10 (in the case of ISBN13). The 'X' in the case of ISBN10 represents a number of 10 in 11-base.

As far as I understand these articles:

https://www.barcodefaq.com/1d/isbn/ https://isbn-information.com/isbn-barcode.html

barcodes will contain the digits of ISBNs, except its last digit, the example the first article gives is

ISBN = 09767736X

Barcode = 9780976773665

What confuses me is the number of 51050 on this picture

enter image description here

I wonder whether it is part of the barcode or not. If we consider it not to be a barcode, then converting a barcode to an ISBN would be trivial:

function convertBarcodeIntoISBN(input) {
    var isbn = {isbn13: input};
    if (input.startsWith("978")) {
        var isbn10 = input.substring(3);
        var checksum = 0;
        var p = 10;
        for (var index = 0; index < 9; index++) {
            checksum += isbn10[index] * (p--);
        }
        checksum = 11 - (checksum % 11);
        if (checksum === 10) checksum = 'X';
        isbn10 += checksum;
        isbn.isbn10 = isbn10;
    }
    return isbn;
}

But if we consider 51050 to be part of the barcode, then we will need to mine the ISBN from the barcode, however, in this case I am not sure how should I operate. The best I can pull from the top of my mind is:

function getLastISBNDigit(input) {
    if ((input.length != 10) && (input.length != 13)) return;
    var is10 = (input.length === 10);
    var sum = 0;
    var p = (is10 ? 11 : 3);
    for (var index = 0; index < input.length - 1; index++) {
        sum += ((input[index] === 'X') ? 10 : input[index]) * (p = (is10 ? (p - 1) : ((p + 2) % 4)));
    }
    var moduloClass = (is10 ? 11 : 10);
    var result = (moduloClass - (sum % moduloClass)) % moduloClass;
    return ((result === 10) ? 'X' : result);
}

function getISBN(input) {
    var isbn = {};
    if (input.length > 13) return getISBN(input.substring(0, 13));
    if (input.length === 10) {
        if (isValidISBN(input)) {
            isbn.isbn10 = input;
            isbn.isbn13 = "978" + input;
            isbn.isbn13 = isbn.isbn13.substring(0, 12) + getLastISBNDigit(isbn.isbn13);
        }
    } else if (input.length === 13) {
        if (isValidISBN(input)) {
            isbn.isbn13 = input;
            if (input.startsWith("978")) {
                isbn.isbn10 = input.substring(3);
                isbn.isbn10 = isbn.isbn10.substring(0, 9) + getLastISBNDigit(isbn.isbn10);
            }
        } else if (input.startsWith("978")) {
            return getISBN(input.substring(3));
        }
    }
    return isbn;
}

This is how I think barcodes should be converted into ISBN and ISBN13 values. Am I right with my reasoning?


Solution

  • The second part is the human-readable price (from this slide):

    enter image description here

    Hence, the first part of your consideration makes sense and 51050 is not part of the barcode! The price of the product is 10.50$.