I'm working on modernizing Rosetta Code's infrastructure. Starting with communications. Please accept this time-limited open invite to RC's Slack.. --Michael Mol (talk) 20:59, 30 May 2020 (UTC)

ISBN13 check digit

From Rosetta Code
Task
ISBN13 check digit
You are encouraged to solve this task according to the task description, using any language you may know.
Task

Validate the check digit of an ISBN-13 code. Multiply every other digit by 3. Add the digits together. Take the remainder of division by 10. If it is 0, the ISBN-13 check digit is correct.

Use the following codes for testing:

978-1734314502: good
978-1734314509: bad
978-1788399081: good
978-1788399083: bad

Show output here, on this page

See also

See https://isbn-information.com/the-13-digit-isbn.html for details on the method of validation.

AppleScript[edit]

Composition of pure functions[edit]

-- isISBN13 :: String -> Bool
on isISBN13(s)
script digitValue
on |λ|(c)
if isDigit(c) then
{c as integer}
else
{}
end if
end |λ|
end script
 
set digits to concatMap(digitValue, characters of s)
 
13 = length of digits ¬
and 0 = sum(zipWith(my mul, digits, cycle({1, 3}))) mod 10
end isISBN13
 
 
---------------------------TEST----------------------------
on run
script test
on |λ|(s)
{s, isISBN13(s)}
end |λ|
end script
 
map(test, {"978-1734314502", "978-1734314509", ¬
"978-1788399081", "978-1788399083"})
end run
 
 
---------------------GENERIC FUNCTIONS---------------------
 
-- concatMap :: (a -> [b]) -> [a] -> [b]
on concatMap(f, xs)
set lng to length of xs
set acc to {}
tell mReturn(f)
repeat with i from 1 to lng
set acc to acc & (|λ|(item i of xs, i, xs))
end repeat
end tell
return acc
end concatMap
 
-- cycle :: [a] -> Generator [a]
on cycle(xs)
script
property lng : 1 + (length of xs)
property i : missing value
on |λ|()
if missing value is i then
set i to 1
else
set nxt to (1 + i) mod lng
if 0 = ((1 + i) mod lng) then
set i to 1
else
set i to nxt
end if
end if
return item i of xs
end |λ|
end script
end cycle
 
-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
tell mReturn(f)
set v to startValue
set lng to length of xs
repeat with i from 1 to lng
set v to |λ|(v, item i of xs, i, xs)
end repeat
return v
end tell
end foldl
 
-- isDigit :: Char -> Bool
on isDigit(c)
set n to (id of c)
48 ≤ n and 57 ≥ n
end isDigit
 
-- length :: [a] -> Int
on |length|(xs)
set c to class of xs
if list is c or string is c then
length of xs
else
(2 ^ 29 - 1) -- (maxInt - simple proxy for non-finite)
end if
end |length|
 
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
-- The list obtained by applying f
-- to each element of xs.
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
 
-- min :: Ord a => a -> a -> a
on min(x, y)
if y < x then
y
else
x
end if
end min
 
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
-- 2nd class handler function lifted into 1st class script wrapper.
if script is class of f then
f
else
script
property |λ| : f
end script
end if
end mReturn
 
-- mul (*) :: Num a => a -> a -> a
on mul(a, b)
a * b
end mul
 
-- sum :: [Num] -> Num
on sum(xs)
script add
on |λ|(a, b)
a + b
end |λ|
end script
 
foldl(add, 0, xs)
end sum
 
-- take :: Int -> [a] -> [a]
-- take :: Int -> String -> String
on take(n, xs)
set c to class of xs
if list is c then
if 0 < n then
items 1 thru min(n, length of xs) of xs
else
{}
end if
else if string is c then
if 0 < n then
text 1 thru min(n, length of xs) of xs
else
""
end if
else if script is c then
set ys to {}
repeat with i from 1 to n
set v to |λ|() of xs
if missing value is v then
return ys
else
set end of ys to v
end if
end repeat
return ys
else
missing value
end if
end take
 
-- zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
on zipWith(f, xs, ys)
set lng to min(|length|(xs), |length|(ys))
if 1 > lng then return {}
set xs_ to take(lng, xs) -- Allow for non-finite
set ys_ to take(lng, ys) -- generators like cycle etc
set lst to {}
tell mReturn(f)
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs_, item i of ys_)
end repeat
return lst
end tell
end zipWith
Output:
{{"978-1734314502", true}, {"978-1734314509", false}, {"978-1788399081", true}, {"978-1788399083", false}}

Straightforward[edit]

This task can be tackled very simply by working through the numeric text two characters at a time:

on validateISBN13(ISBN13)
if (ISBN13's class is not text) then return false
 
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to {"-", space}
set ISBN13 to ISBN13's text items
set AppleScript's text item delimiters to ""
set ISBN13 to ISBN13 as text
set AppleScript's text item delimiters to astid
 
if (((count ISBN13) is not 13) or (ISBN13 contains ".") or (ISBN13 contains ",")) then return false
try
ISBN13 as number
on error
return false
end try
 
set sum to 0
repeat with i from 1 to 12 by 2
set sum to sum + (character i of ISBN13) + (character (i + 1) of ISBN13) * 3 -- Automatic text-to-number coercions.
end repeat
 
return ((sum + (character 13 of ISBN13)) mod 10 = 0)
end validateISBN13
 
-- Test:
set output to {}
set verdicts to {"bad", "good"}
repeat with thisISBN13 in {"978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083"}
set isValid to validateISBN13(thisISBN13)
set end of output to thisISBN13 & ": " & item ((isValid as integer) + 1) of verdicts
end repeat
 
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to linefeed
set output to output as text
set AppleScript's text item delimiters to astid
return output
Output:
"978-1734314502: good
978-1734314509: bad
978-1788399081: good
978-1788399083: bad"

Or it can be handled purely numerically. Since the "weights" alternate and are palindromic, it makes no difference whether the last digit or the first is treated as the check digit. In fact, if preferred, the repeat below can go round 7 times with the return line as simply: return (sum mod 10 = 0).

on validateISBN13(ISBN13)
if (ISBN13's class is not text) then return false
 
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to {"-", space}
set ISBN13 to ISBN13's text items
set AppleScript's text item delimiters to ""
set ISBN13 to ISBN13 as text
set AppleScript's text item delimiters to astid
 
if (((count ISBN13) is not 13) or (ISBN13 contains ".") or (ISBN13 contains ",")) then return false
try
set ISBN13 to ISBN13 as number
on error
return false
end try
 
set sum to 0
repeat 6 times
set sum to sum + ISBN13 mod 10 + ISBN13 mod 100 div 10 * 3
set ISBN13 to ISBN13 div 100
end repeat
 
return ((sum + ISBN13) mod 10 = 0)
end validateISBN13

AWK[edit]

 
# syntax: GAWK -f ISBN13_CHECK_DIGIT.AWK
BEGIN {
arr[++n] = "978-1734314502"
arr[++n] = "978-1734314509"
arr[++n] = "978-1788399081"
arr[++n] = "978-1788399083"
arr[++n] = "9780820424521"
arr[++n] = "0820424528"
for (i=1; i<=n; i++) {
printf("%s %s\n",arr[i],isbn13(arr[i]))
}
exit(0)
}
function isbn13(isbn, check_digit,i,sum) {
gsub(/[ -]/,"",isbn)
if (length(isbn) != 13) { return("NG length") }
for (i=1; i<=12; i++) {
sum += substr(isbn,i,1) * (i % 2 == 1 ? 1 : 3)
}
check_digit = 10 - (sum % 10)
return(substr(isbn,13,1) == check_digit ? "OK" : sprintf("NG check digit S/B %d",check_digit))
}
 
Output:
978-1734314502 OK
978-1734314509 NG check digit S/B 2
978-1788399081 OK
978-1788399083 NG check digit S/B 1
9780820424521 OK
0820424528 NG length

C[edit]

#include <stdio.h>
 
int check_isbn13(const char *isbn) {
int ch = *isbn, count = 0, sum = 0;
/* check isbn contains 13 digits and calculate weighted sum */
for ( ; ch != 0; ch = *++isbn, ++count) {
/* skip hyphens or spaces */
if (ch == ' ' || ch == '-') {
--count;
continue;
}
if (ch < '0' || ch > '9') {
return 0;
}
if (count & 1) {
sum += 3 * (ch - '0');
} else {
sum += ch - '0';
}
}
if (count != 13) return 0;
return !(sum%10);
}
 
int main() {
int i;
const char* isbns[] = {"978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083"};
for (i = 0; i < 4; ++i) {
printf("%s: %s\n", isbns[i], check_isbn13(isbns[i]) ? "good" : "bad");
}
return 0;
}
Output:
978-1734314502: good
978-1734314509: bad
978-1788399081: good
978-1788399083: bad

Factor[edit]

USING: combinators.short-circuit formatting kernel math
math.functions math.parser math.vectors qw sequences
sequences.extras sets unicode ;
 
: (isbn13?) ( str -- ? )
string>digits
[ <evens> sum ] [ <odds> 3 v*n sum + ] bi 10 divisor? ;
 
: isbn13? ( str -- ? )
"- " without
{ [ length 13 = ] [ [ digit? ] all? ] [ (isbn13?) ] } 1&& ;
 
qw{ 978-1734314502 978-1734314509 978-1788399081 978-1788399083 }
[ dup isbn13? "good" "bad" ? "%s: %s\n" printf ] each
Output:
978-1734314502: good
978-1734314509: bad
978-1788399081: good
978-1788399083: bad

Go[edit]

package main
 
import (
"fmt"
"strings"
"unicode/utf8"
)
 
func checkIsbn13(isbn string) bool {
// remove any hyphens or spaces
isbn = strings.ReplaceAll(strings.ReplaceAll(isbn, "-", ""), " ", "")
// check length == 13
le := utf8.RuneCountInString(isbn)
if le != 13 {
return false
}
// check only contains digits and calculate weighted sum
sum := int32(0)
for i, c := range isbn {
if c < '0' || c > '9' {
return false
}
if i%2 == 0 {
sum += c - '0'
} else {
sum += 3 * (c - '0')
}
}
return sum%10 == 0
}
 
func main() {
isbns := []string{"978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083"}
for _, isbn := range isbns {
res := "bad"
if checkIsbn13(isbn) {
res = "good"
}
fmt.Printf("%s: %s\n", isbn, res)
}
}
Output:
978-1734314502: good
978-1734314509: bad
978-1788399081: good
978-1788399083: bad

Haskell[edit]

import Data.Char (isDigit, digitToInt)
import Control.Monad (forM_)
import Text.Printf (printf)
 
testISBNs :: [String]
testISBNs = ["978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083"]
 
pair :: Num a => [a] -> [(a, a)]
pair [] = []
pair xs = p (take 2 xs) : pair (drop 2 xs)
where p ps = case ps of (x:y:zs) -> (x,y)
(x:zs) -> (x,0)
 
validIsbn13 :: String -> Bool
validIsbn13 isbn
| length (digits isbn) /= 13 = False
| otherwise = calc isbn `rem` 10 == 0
where digits = map digitToInt . filter isDigit
calc = foldl (\a (x, y) -> x + y * 3 + a) 0 . pair . digits
 
main :: IO ()
main = forM_ testISBNs (\isbn -> printf "%s: Valid: %s\n" isbn (show $ validIsbn13 isbn))
Output:
978-1734314502: Valid: True
978-1734314509: Valid: False
978-1788399081: Valid: True
978-1788399083: Valid: False

Or, expressed in terms of cycle:

import Data.Char (digitToInt, isDigit)
 
isISBN13 :: String -> Bool
isISBN13 =
(0 ==) .
flip rem 10 .
sum . flip (zipWith ((*) . digitToInt) . filter isDigit) (cycle [1, 3])
 
main :: IO ()
main =
mapM_ print $
((,) <*> isISBN13) <$>
["978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083"]
Output:
("978-1734314502",True)
("978-1734314509",False)
("978-1788399081",True)
("978-1788399083",False)

Julia[edit]

function isbncheck(str)
return sum(iseven(i) ? 3 * parse(Int, ch) : parse(Int, ch)
for (i, ch) in enumerate(replace(str, r"\D" => ""))) % 10 == 0
end
 
const testingcodes = ["978-1734314502", "978-1734314509",
"978-1788399081", "978-1788399083"]
 
for code in testingcodes
println(code, ": ", isbncheck(code) ? "good" : "bad")
end
 
Output:
978-1734314502: good
978-1734314509: bad
978-1788399081: good
978-1788399083: bad

langur[edit]

Works with: langur version 0.8.11

In this example, we map to multiple functions (actually 1 no-op).

val .isbn13checkdigit = f(var .s) {
.s = replace(.s, RE/[\- ]/)
matching(re/^[0-9]{13}$/, .s) and
fold(f{+}, map [_, f{x 3}], s2n .s) div 10
}
 
val .tests = h{
"978-1734314502": true,
"978-1734314509": false,
"978-1788399081": true,
"978-1788399083": false,
}
 
for .key of .tests {
val .pass = .isbn13checkdigit(.key)
write .key, ": ", if(.pass: "good"; "bad")
writeln if(.pass == .tests[.key]: ""; " (ISBN-13 CHECK DIGIT TEST FAILED)")
}
Works with: langur version 0.9.0

In this example, we set a for loop value as it progresses.

val .isbn13checkdigit = f(var .s) {
.s = replace(.s, RE/[\- ]/)
var .alt = true
matching(re/^[0-9]{13}$/, .s) and
for[=0] .d in s2n(.s) { _for += if(not= .alt: .d x 3; .d) } div 10
}
 
val .tests = h{
"978-1734314502": true,
"978-1734314509": false,
"978-1788399081": true,
"978-1788399083": false,
}
 
for .key of .tests {
val .pass = .isbn13checkdigit(.key)
write .key, ": ", if(.pass: "good"; "bad")
writeln if(.pass == .tests[.key]: ""; " (ISBN-13 CHECK DIGIT TEST FAILED)")
}
Output:
978-1734314502: good
978-1734314509: bad
978-1788399081: good
978-1788399083: bad

Nanoquery[edit]

Translation of: Go
def checkIsbn13(isbn)
// remove any hyphens or spaces
isbn = str(isbn).replace("-","").replace(" ","")
 
// check length = 13
if len(isbn) != 13
return false
end
 
// check only contains digits and calculate weighted sum
sum = 0
for i in range(0, len(isbn) - 1)
c = isbn[i]
if (ord(c) < ord("0")) or (ord(c) > ord("9"))
return false
end
 
if (i % 2) = 0
sum += ord(c) - ord("0")
else
sum += 3 * (ord(c) - ord("0"))
end
end
 
return (sum % 10) = 0
end
 
isbns = {"978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083"}
for isbn in isbns
res = "bad"
if checkIsbn13(isbn)
res = "good"
end
 
print format("%s: %s\n", isbn, res)
end
Output:
978-1734314502: good
978-1734314509: bad
978-1788399081: good
978-1788399083: bad

Perl[edit]

use strict;
use warnings;
use feature 'say';
 
sub check_digit {
my($isbn) = @_; my($sum);
$sum += (1,3)[$_%2] * (split '', join '', split /\D/, $isbn)[$_] for 0..11;
(10 - $sum % 10) % 10;
}
 
for (<978-1734314502 978-1734314509 978-1788399081 978-1788399083 978-2-74839-908-0 978-2-74839-908-5>) {
my($isbn,$check) = /(.*)(.)/;
my $check_d = check_digit($isbn);
say "$_ : " . ($check == $check_d ? 'Good' : "Bad check-digit $check; should be $check_d")
}
Output:
978-1734314502 : Good
978-1734314509 : Bad check-digit 9; should be 2
978-1788399081 : Good
978-1788399083 : Bad check-digit 3; should be 1
978-2-74839-908-0 : Good
978-2-74839-908-5 : Bad check-digit 5; should be 0

Phix[edit]

procedure check_isbn13(string isbn)
integer digits = 0, checksum = 0, w = 1
for i=1 to length(isbn) do
integer ch = isbn[i]
if ch!=' ' and ch!='-' then
ch -= '0'
if ch<0 or ch>9 then checksum = 9 exit end if
checksum += ch*w
digits += 1
w = 4-w
end if
end for
checksum = remainder(checksum,10)
string gb = iff(digits=13 and checksum=0 ? "good" : "bad")
printf(1,"%s: %s\n",{isbn,gb})
end procedure
 
constant isbns = {"978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083",
"978-2-74839-908-0","978-2-74839-908-5","978 1 86197 876 9"}
for i=1 to length(isbns) do check_isbn13(isbns[i]) end for
Output:
978-1734314502: good
978-1734314509: bad
978-1788399081: good
978-1788399083: bad
978-2-74839-908-0: good
978-2-74839-908-5: bad
978 1 86197 876 9: good

PicoLisp[edit]

(de isbn13? (S)
(let L
(make
(for N (chop S)
(and (format N) (link @)) ) )
(and
(= 13 (length L))
(=0 (% (sum * L (circ 1 3)) 10)) ) ) )
(mapc
'((A)
(tab
(-19 1)
A
(if (isbn13? A) 'ok 'fail) ) )
(quote
"978-1734314502"
"978-1734314509"
"978-1-86197-876-9"
"978-2-74839-908-5"
"978 1 86197 876 9" ) )
Output:
978-1734314502     ok
978-1734314509     fail
978-1-86197-876-9  ok
978-2-74839-908-5  fail
978 1 86197 876 9  ok

Python[edit]

def is_isbn13(n):
n = n.replace('-','').replace(' ', '')
if len(n) != 13:
return False
product = (sum(int(ch) for ch in n[::2])
+ sum(int(ch) * 3 for ch in n[1::2]))
return product % 10 == 0
 
if __name__ == '__main__':
tests = '''
978-1734314502
978-1734314509
978-1788399081
978-1788399083'''
.strip().split()
for t in tests:
print(f"ISBN13 {t} validates {is_isbn13(t)}")
Output:
ISBN13 978-1734314502 validates True
ISBN13 978-1734314509 validates False
ISBN13 978-1788399081 validates True
ISBN13 978-1788399083 validates False


Or, expressed in terms of itertools.cycle

'''ISBN13 check digit'''
 
from itertools import cycle
from operator import mul
 
 
# isISBN13 :: String -> Bool
def isISBN13(s):
'''True if the digits of s form
a valid ISBN-13 code.
'''

digits = [int(c) for c in s if c.isdigit()]
return 13 == len(digits) and 0 == sum(
map(
mul,
digits,
cycle([1, 3])
)
) % 10
 
 
# ---------------------------TEST---------------------------
# main :: IO ()
def main():
'''Validation of four strings:'''
 
for s in ['978-1734314502', '978-1734314509',
'978-1788399081', '978-1788399083']:
print((s, isISBN13(s)))
 
 
# MAIN ---
if __name__ == '__main__':
main()
Output:
('978-1734314502', True)
('978-1734314509', False)
('978-1788399081', True)
('978-1788399083', False)

Raku[edit]

(formerly Perl 6)

Works with: Rakudo version 2019.11

Also test a value that has a zero check digit.

sub check-digit ($isbn) {
(10 - (sum (|$isbn.comb(/<[0..9]>/)) »*» (1,3)) % 10).substr: *-1
}
 
{
my $check = .substr(*-1);
my $check-digit = check-digit .chop;
say "$_ : ", $check == $check-digit ??
'Good' !!
"Bad check-digit $check; should be $check-digit"
} for words <
978-1734314502
978-1734314509
978-1788399081
978-1788399083
978-2-74839-908-0
978-2-74839-908-5
>;
Output:
978-1734314502 : Good
978-1734314509 : Bad check-digit 9; should be 2
978-1788399081 : Good
978-1788399083 : Bad check-digit 3; should be 1
978-2-74839-908-0 : Good
978-2-74839-908-5 : Bad check-digit 5; should be 0

REXX[edit]

A couple of additional checks were made to verify a correct length,   and also that the ISBN-13 code is all numerics   (with optional minus signs).

/*REXX pgm validates the check digit of an ISBN─13 code  (it may have embedded minuses).*/
parse arg $ /*obtain optional arguments from the CL*/
if $='' | if $="," then $= '978-1734314502 978-1734314509 978-1788399081 978-1788399083'
@ISBN= "ISBN─13 code isn't" /*a literal used when displaying msgs. */
/* [↓] remove all minuses from X code.*/
do j=1 for words($); y= word($,j) /*obtain an ISBN─13 code from $ list.*/
x= space( translate(y, , '-'), 0) /*remove all minus signs from the code.*/
L= length(x) /*obtain the length of the ISBN-13 code*/
if L \== 13 then do; say @ISBN '13 characters: ' x; exit 13; end
if verify(x, 9876543210)\==0 then do; say @ISBN 'numeric: ' x; exit 10; end
sum= 0
do k=1 for L; #= substr(x, k, 1) /*get a decimal digit from the X code. */
if \(k//2) then #= # * 3 /*multiply every other digit by three. */
sum= sum + # /*add the digit (or product) to the SUM*/
end /*k*/
 
if right(sum, 1)==0 then say ' ISBN-13 code ' x " is valid."
else say ' ISBN-13 code ' x " isn't valid."
end /*j*/ /*stick a fork in it, we're all done. */
output   when using the four default inputs:
     ISBN-13 code  9781734314502     is valid.
     ISBN-13 code  9781734314509  isn't valid.
     ISBN-13 code  9781788399081     is valid.
     ISBN-13 code  9781788399083  isn't valid.

Swift[edit]

func checkISBN(isbn: String) -> Bool {
guard !isbn.isEmpty else {
return false
}
 
let sum = isbn
.compactMap({ $0.wholeNumberValue })
.enumerated()
.map({ $0.offset & 1 == 1 ? 3 * $0.element : $0.element })
.reduce(0, +)
 
return sum % 10 == 0
}
 
let cases = [
"978-1734314502",
"978-1734314509",
"978-1788399081",
"978-1788399083"
]
 
for isbn in cases {
print("\(isbn) => \(checkISBN(isbn: isbn) ? "good" : "bad")")
}


Output:
978-1734314502 => good
978-1734314509 => bad
978-1788399081 => good
978-1788399083 => bad

XPL0[edit]

include xpllib;         \contains StrLen function
 
proc ISBN13(Str); \Show if International Standard Book Number is good
char Str;
int Sum, Cnt, Dig, I;
[Sum:= 0; Cnt:= 0;
for I:= 0 to StrLen(Str)-1 do
[Dig:= Str(I) - ^0;
if Dig>=0 & Dig<=9 then
[Sum:= Sum + Dig;
Cnt:= Cnt + 1;
if (Cnt&1) = 0 then
Sum:= Sum + Dig + Dig;
];
];
Text(0, Str);
Text(0, if rem(Sum/10)=0 & Cnt=13 then ": good" else ": bad");
CrLf(0);
];
 
[ISBN13("978-1734314502");
ISBN13("978-1734314509");
ISBN13("978-1788399081");
ISBN13("978-1788399083");
ISBN13("978-1-59327-220-3");
ISBN13("978-178839918");
]
Output:
978-1734314502: good
978-1734314509: bad
978-1788399081: good
978-1788399083: bad
978-1-59327-220-3: good
978-178839918: bad

zkl[edit]

fcn ISBN13_check(isbn){  // "978-1734314502", throws on invalid digits
var [const] one3=("13"*6 + 1).split("").apply("toInt"); // examine 13 digits
// one3=("13"*6) if you want to calculate what the check digit should be
one3.zipWith('*,isbn - " -").sum(0) % 10 == 0
}
isbns:=
#<<<"
978-1734314502
978-1734314509
978-1788399081
978-1788399083
978-2-74839-908-0
978-2-74839-908-5".split("\n");
#<<<
foreach isbn in (isbns)
{ println(isbn.strip()," ",ISBN13_check(isbn) and " Good" or " Bad") }
Output:
978-1734314502   Good
978-1734314509   Bad
978-1788399081   Good
978-1788399083   Bad
978-2-74839-908-0   Good
978-2-74839-908-5   Bad