PWC 162 › ISBN-13

This post is part of a series on Mohammad Anwar’s excellent Weekly Challenge, where hackers submit solutions in Perl, Raku, or any other language, to two different challenges every week. (It’s a lot of fun, if you’re into that sort of thing.)

This week‘s first task is simple: validate ISBN-13 codes.

ISBNs have been around for a long time and come in many different flavours. ISBN-13 is a thirteen-digit code consisting of twelve digits plus a check digit. The checksum calculation is simple. Given the digits x1, x2, …, x12, and the check digit, x13:

(10 – (x1 + 3x2 + x3 + 3x4 + … + x11 + 3x12 + x13)) ≡ 0 (mod 10)

To make calculation a little easier, we can move the check digit (x13) out of the sum and compare it at the end. For example, given the code 978-0-306-40615-7, we can calculate:

10 – (9 + 3×7 + 8 + 3×0 + 3 + 3×0 + 6 + 3×4 + 0 + 3×6 + 1 + 3×5) % 10) = 7

Using List::Util‘s pairmap function, we can simplify the calculation significantly:

10 - (sum pairmap { $a + 3*$b } @digits) % 10 == $check;

Most of the function is just error checking and input filtering, which could be improved:

sub valid_isbn13 {
    local $_ = shift;
    croak "Invalid ISBN" unless /^[0-9-]+$/;
    my @digits = grep { /\d/ } split //;
    croak "Only 13 digit ISBNs are supported" if @digits != 13;
    my $check = pop @digits;

    # Sum of every odd number plus 3 x every even number
    10 - (sum pairmap { $a + 3*$b } @digits) % 10 == $check;
}

Leave a Reply

Your email address will not be published. Required fields are marked *