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;
}