# ISBN13 check digit

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

Validate the check digit of an ISBN-13 code:

•   Multiply every other digit by  3.
•   Add these numbers and the other digits.
•   Take the remainder of this number after division by  10.
•   If it is  0,   the ISBN-13 check digit is correct.

You might use the following codes for testing:

•   978-0596528126       (good)
•   978-1788399081       (good)

## 11l

Translation of: Python
```F is_isbn13(=n)
n = n.replace(‘-’, ‘’).replace(‘ ’, ‘’)
I n.len != 13
R 0B
V product = sum(n[(0..).step(2)].map(ch -> Int(ch)))
+ sum(n[(1..).step(2)].map(ch -> Int(ch) * 3))
R product % 10 == 0

V tests = |‘978-1734314502
978-1734314509
978-1788399081
978-1788399083’.split("\n")

L(t) tests
print(‘ISBN13 ’t‘ validates ’is_isbn13(t))```
Output:
```ISBN13 978-1734314502 validates 1B
ISBN13 978-1734314509 validates 0B
ISBN13 978-1788399081 validates 1B
ISBN13 978-1788399083 validates 0B
```

## 8080 Assembly

```	org	100h
jmp	demo
;;;	---------------------------------------------------------------
;;;	Check if the string at BC is a valid ISBN-13 code.
;;;	Carry set if true, clear if not.
isbn13:	lxi	h,0	; HL = accumulator
mov	d,h	; D = 0 (such that if E=A, DE=A).
call	isbngc	; Get first character
rnc		; Carry clear = invalid
call	isbngc	; Get second character
rnc		; Carry clear = invalid
call	isbngc	; Get third character
rnc		; Carry clear = invalid
ldax	b	; Fourth character should be a dash '-'
inx	b
cpi	'-'
stc		; Clear carry w/o touching other flags
cmc
rnz		; If not equal, invalid.
push	h	; Keep loop counter on stack
mvi	l,5	; 5 times 2 characters
isbnlp:	xthl		; Accumulator in HL
call	isbngc	; Get even character
jnc	isbnex	; If invalid, stop
call	isbngc	; Get odd character
jnc	isbnex	; If invalid, stop
xthl		; Loop counter in (H)L
dcr	l	; Done yet?
jnz	isbnlp	; If not, do next two characters
pop	h	; Get accumulator
lxi	d,-10	; Trial division by ten
isbndv:	dad	d	; Subtract 10
jc	isbndv 	; Until zero passed
mov	a,l	; Move low byte to A
adi	10 	; Add ten back (the mod loop went one step too far)
rz		; If zero, return (carry will have been set)
ana	a	; Otherwise, make sure carry is clear
ret		; And then return
isbnex:	pop	h	; Test failed - throw away accumulator and return
ret
isbngc:	ldax	b	; Get character from [BC]
inx	b	; Increment BC
sui	'0'	; Subtract ASCII '0' to get digit value
cpi	10	; If 10 or higher (unsigned), invalid digit.
mov	e,a	; Set (D)E = value
ret
;;;	---------------------------------------------------------------
;;;	Demo: see if the CP/M command line contains a valid ISBN13
;;; 	code.
demo:	lxi	b,82h	; Start of command line argument, skipping first space
call	isbn13	; Is it valid?
mvi	c,9	; CP/M print string
lxi	d,good	; If carry is set, then yes
jc	5
jmp	5
good:	db	'good\$'
Output:
```A>isbn13 978-1734314502
good
A>isbn13 978-1734314509
A>isbn13 978-1788399081
good
A>isbn13 978-1788399083

## 8086 Assembly

```	cpu	8086
bits	16
org	100h
section	.text
jmp	demo
isbn13:	;;;	---------------------------------------------------------------
;;;	Check if the string at DS:SI is a valid ISBN-13 code.
;;;	Carry set if true, clear if false.
xor	dx,dx		; DX = running total
xor	ah,ah		; Set AH=0 so that AX=AL
call	.digit		; Get first digit and add to DX
call	.digit		; Get second digit and add to DX
call	.digit		; Get third digit and add to DX
lodsb			; Fourth character should be a '-'
cmp	al,'-'
jne	.fail 		; If not equal, fail
mov	cx,5 		; Then loop 5 times for the next 10 digits
.loop:	call	.digit		; Get even digit and add to DX
call	.digit		; Get odd digit and add to DX
loop	.loop		; Do this 5 times
mov	ax,dx		; Divide running total by 10
mov	dl,10
div	dl
test	ah,ah		; Is the remainder zero?
jnz	.out		; If not, stop (TEST clears carry)
stc			; Otherwise, set carry and return
ret
.digit:	lodsb			; Get first character
sub	al,'0'		; Subtract ASCII 0 to get digit value
cmp	al,9
ja	.dfail
ret
.dfail:	pop	dx		; Remove return pointer for .digit from stack
.fail:	clc			; Failure - clear carry
.out:	ret
;;;	---------------------------------------------------------------
;;;	Demo: see if the MS-DOS command line contains a valid ISBN13
;;;	code.
demo:	mov	si,82h		; Start of command line argument skipping space
call	isbn13		; Is it valid?
mov	ah,9		; MS-DOS print string
mov	dx,good		; If carry is set, it is good
jc	.print
.print:	int	21h
ret
section	.data
good:	db	'good\$'
```
Output:
```C:\>isbn13 978-1734314502
good
C:\>isbn13 978-1734314509
C:\>isbn13 978-1788399081
good
C:\>isbn13 978-1788399083

## Action!

```INCLUDE "D2:CHARTEST.ACT" ;from the Action! Tool Kit

BYTE FUNC CheckISBN13(CHAR ARRAY t)
BYTE i,index,sum,v

sum=0 index=0
FOR i=1 TO t(0)
DO
v=t(i)
IF IsDigit(v) THEN
v==-'0
IF index MOD 2=1 THEN
v==*3
FI
sum==+v
index==+1
ELSEIF v#'  AND v#'- THEN
RETURN (0)
FI
OD
IF index#13 OR sum MOD 10#0 THEN
RETURN (0)
FI
RETURN (1)

PROC Test(CHAR ARRAY t)
BYTE correct

correct=CheckISBN13(t)
Print(t) Print(" is ")
IF correct THEN
PrintE("correct")
ELSE
PrintE("incorrect")
FI
RETURN

PROC Main()
Put(125) PutE() ;clear screen

Test("978-1734314502")
Test("978-1734314509")
Test("978-1788399081")
Test("978-1788399083")
RETURN```
Output:
```978-1734314502 is correct
978-1734314509 is incorrect
978-1788399081 is correct
978-1788399083 is incorrect
```

```with Ada.Text_IO;

procedure ISBN_Check is

function Is_Valid (ISBN : String) return Boolean is
Odd       : Boolean := True;
Sum       : Integer := 0;
Value     : Integer;
begin
for I in ISBN'Range loop
if ISBN (I) in '0' .. '9' then
Value := Character'Pos (ISBN (I)) - Character'Pos ('0');
if Odd then
Sum := Sum + Value;
else
Sum := Sum + 3 * Value;
end if;
Odd := not Odd;
end if;
end loop;
return Sum mod 10 = 0;
end Is_Valid;

procedure Show (ISBN : String) is
Valid : constant Boolean := Is_Valid (ISBN);
begin
Put (ISBN); Put ("  ");
Put ((if Valid then "Good" else "Bad"));
New_Line;
end Show;
begin
Show ("978-1734314502");
Show ("978-1734314509");
Show ("978-1788399081");
Show ("978-1788399083");
end ISBN_Check;
```
Output:
```978-1734314502  Good
978-1788399081  Good

## ALGOL 68

Works with: ALGOL 68G version Any - tested with release 2.8.3.win32
```BEGIN # Check some IsBN13 check digits                                         #
# returns TRUE if the alledged isbn13 has the correct check sum,           #
#         FALSE otherwise                                                  #
#         non-digit characters are ignored and there must be 13 digits     #
PROC check isbn13 = ( STRING isbn13 )BOOL:
BEGIN
INT sum          := 0;
INT digits       := 0;
BOOL other digit := FALSE;
FOR pos FROM LWB isbn13 TO UPB isbn13 DO
IF CHAR c = isbn13[ pos ];
c >= "0" AND c <= "9"
THEN
# have another digit                                       #
digits +:= 1;
sum    +:= ( ABS c - ABS "0" ) * IF other digit THEN 3 ELSE 1 FI;
other digit := NOT other digit
FI
OD;
digits = 13 AND sum MOD 10 = 0
END; # check isbn13 #
[]STRING tests    = ( "978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083" );
[]BOOL   expected = (             TRUE,            FALSE,             TRUE,            FALSE );
FOR pos FROM LWB tests TO UPB tests DO
BOOL result = check isbn13( tests[ pos ] );
print( ( tests[ pos ]
, ": "
, IF result THEN "good" ELSE "bad" FI
, IF result = expected[ pos ] THEN "" ELSE " NOT AS EXPECTED" FI
, newline
)
)
OD
END```
Output:
```978-1734314502: good
978-1788399081: good
```

## APL

Works with: Dyalog APL
```check_isbn13←{
13≠⍴n←(⍵∊⎕D)/⍵:0
0=10|(⍎¨n)+.×13⍴1 3
}
```
Output:
```      check_isbn13¨ '978-1734314502' '978-1734314509' '978-1788399081' '978-1788399083'
1 0 1 0```

## AppleScript

### Composition of pure functions

```-------------------- ISBN13 CHECK DIGIT --------------------

-- 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)
on |λ|(a, b)
a + b
end |λ|
end script

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

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 {}
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-1788399081: good

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
```

## Arturo

```validISBN?: function [isbn][
currentCheck: to :integer to :string last isbn
isbn: map split chop replace isbn "-" "" 'd -> to :integer d

s: 0
loop.with:'i isbn 'n [
if? even? i -> s: s + n
else -> s: s + 3*n
]
checkDigit: 10 - s % 10
return currentCheck = checkDigit
]

tests: [
"978-1734314502" "978-1734314509"
"978-1788399081" "978-1788399083"
]

loop tests 'test [
print [test "=>" validISBN? test]
]
```
Output:
```978-1734314502 => true
978-1734314509 => false
978-1788399081 => true
978-1788399083 => false```

## AutoHotkey

```ISBN13_check_digit(n){
for i, v in StrSplit(RegExReplace(n, "[^0-9]"))
sum += !Mod(i, 2) ? v*3 : v
return n "`t" (Mod(sum, 10) ? "(bad)" : "(good)")
}
```
Examples:
```output := ""
nums := ["978-1734314502","978-1734314509","978-1788399081","978-1788399083"]
for i, n in nums
output .= ISBN13_check_digit(n) "`n"
MsgBox % output
return
```
Output:
```978-1734314502	(good)
978-1788399081	(good)

## AWK

```# 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
```

## BASIC256

Translation of: Ring
```arraybase 1
dim isbn = {"978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083", "978-2-74839-908-0", "978-2-74839-908-5", "978 1 86197 876 9"}

for n = 1 to isbn[?]
sum = 0
isbnStr = isbn[n]
isbnStr = replace(isbnStr, "-", "")
isbnStr = replace(isbnStr, " ", "")
for m = 1 to length(isbnStr)
if m mod 2 = 0 then
num = 3 * int(mid(isbnStr, m, 1))
else
num = int(mid(isbnStr, m, 1))
end if
sum += num
next m
if sum mod 10 = 0 then
print isbn[n]; ": good"
else
end if
next n```

## BCPL

```get "libhdr"

let checkISBN(s) = valof
\$(  let tally = 0
unless s%0 = 14 resultis false
unless s%4 = '-' resultis false

for i=1 to 3
\$(  let digit = s%i-'0'
test i rem 2 = 0
do tally := tally + 3 * digit
or tally := tally + digit
\$)

for i=5 to 14
\$(  let digit = s%i-'0'
test i rem 2 = 0
do tally := tally + digit
or tally := tally + 3 * digit
\$)

resultis tally rem 10 = 0
\$)

let show(s) be
writef("%S: %S*N", s, checkISBN(s) -> "good", "bad")

let start() be
\$(  show("978-1734314502")
show("978-1734314509")
show("978-1788399081")
show("978-1788399083")
\$)```
Output:
```978-1734314502: good
978-1788399081: good

## C

```#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-1788399081: good
```

## C++

Translation of: C
```#include <iostream>

bool check_isbn13(std::string isbn) {
int count = 0;
int sum = 0;

for (auto ch : isbn) {
/* skip hyphens or spaces */
if (ch == ' ' || ch == '-') {
continue;
}
if (ch < '0' || ch > '9') {
return false;
}
if (count & 1) {
sum += 3 * (ch - '0');
} else {
sum += ch - '0';
}
count++;
}

if (count != 13) {
return false;
}
return sum % 10 == 0;
}

int main() {
auto isbns = { "978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083" };
for (auto isbn : isbns) {
std::cout << isbn << ": " << (check_isbn13(isbn) ? "good" : "bad") << '\n';
}

return 0;
}
```
Output:
```978-1734314502: good
978-1788399081: good

## C#

```using System;
using System.Linq;

public class Program
{
public static void Main() {
Console.WriteLine(CheckISBN13("978-1734314502"));
Console.WriteLine(CheckISBN13("978-1734314509"));
Console.WriteLine(CheckISBN13("978-1788399081"));
Console.WriteLine(CheckISBN13("978-1788399083"));

static bool CheckISBN13(string code) {
code = code.Replace("-", "").Replace(" ", "");
if (code.Length != 13) return false;
int sum = 0;
foreach (var (index, digit) in code.Select((digit, index) => (index, digit))) {
if (char.IsDigit(digit)) sum += (digit - '0') * (index % 2 == 0 ? 1 : 3);
else return false;
}
return sum % 10 == 0;
}
}
}
```
Output:
```True
False
True
False```

## CLU

```isbn13_check = proc (s: string) returns (bool)
if string\$size(s) ~= 14 then return(false) end
if s[4] ~= '-' then return(false) end
begin
check: int := 0
for i: int in int\$from_to(1, 14) do
if i=4 then continue end
d: int := int\$parse(string\$c2s(s[i]))
if i=2 cor (i>4 cand i//2=1) then d := d*3 end
check := check + d
end
return(check//10 = 0)
return(false)
end
end isbn13_check

start_up = proc ()
po: stream := stream\$primary_output()
tests: array[string] := array[string]\$
["978-1734314502",
"978-1734314509",
"978-1788399081",
"978-1788399083"]

for test: string in array[string]\$elements(tests) do
stream\$puts(po, test)
stream\$puts(po, ": ")
if isbn13_check(test)
then stream\$putl(po, "good")
end
end
end start_up```
Output:
```978-1734314502: good
978-1788399081: good

## COBOL

Works with: GnuCOBOL
```      ******************************************************************
* Author: Jay Moseley
* Date: November 10, 2019
* Purpose: Testing various subprograms/ functions.
* Tectonics: cobc -xj testSubs.cbl
******************************************************************
IDENTIFICATION DIVISION.

PROGRAM-ID. testSubs.
ENVIRONMENT DIVISION.

CONFIGURATION SECTION.
REPOSITORY.
FUNCTION ALL INTRINSIC
FUNCTION validISBN13.

INPUT-OUTPUT SECTION.
FILE-CONTROL.

DATA DIVISION.

FILE SECTION.

WORKING-STORAGE SECTION.

01  IX                          PIC S9(4) COMP.
01  TEST-ISBNS.
02  FILLER                  PIC X(14) VALUE '978-1734314502'.
02  FILLER                  PIC X(14) VALUE '978-1734314509'.
02  FILLER                  PIC X(14) VALUE '978-1788399081'.
02  FILLER                  PIC X(14) VALUE '978-1788399083'.
01  TEST-ISBN                   REDEFINES TEST-ISBNS
OCCURS 4 TIMES
PIC X(14).

PROCEDURE DIVISION.

MAIN-PROCEDURE.

PERFORM
VARYING IX
FROM 1
BY 1
UNTIL IX > 4

DISPLAY TEST-ISBN (IX) '   ' WITH NO ADVANCING
END-DISPLAY
IF validISBN13(TEST-ISBN (IX)) = -1
ELSE
DISPLAY '(good)'
END-IF

END-PERFORM.

GOBACK.

END PROGRAM testSubs.

******************************************************************
* Author: Jay Moseley
* Date: May 19, 2016
* Purpose: validate ISBN-13 (International Standard
*          Book Number).
******************************************************************
IDENTIFICATION DIVISION.

FUNCTION-ID. validISBN13.
ENVIRONMENT DIVISION.

CONFIGURATION SECTION.
REPOSITORY.
FUNCTION ALL INTRINSIC.

INPUT-OUTPUT SECTION.
FILE-CONTROL.

DATA DIVISION.

FILE SECTION.

WORKING-STORAGE SECTION.

01  PASSED-SIZE                 PIC S9(6) COMP-5.
01  IX                          PIC S9(4) COMP.

01  WORK-FIELDS.
02  WF-DIGIT                PIC X.
02  WF-COUNT                PIC 9(2).
88  WEIGHT-1  VALUE 1, 3, 5, 7, 9, 11, 13.
88  WEIGHT-3  VALUE 2, 4, 6, 8, 10, 12.
02  WF-SUM                  PIC S9(8) COMP.

01  PASSED-ISBN                 PIC X ANY LENGTH.
01  RETURN-VALUE                PIC S9.

PROCEDURE DIVISION USING PASSED-ISBN
RETURNING RETURN-VALUE.

CALL 'C\$PARAMSIZE'
USING 1
GIVING PASSED-SIZE
END-CALL.

COMPUTE-CKDIGIT.

INITIALIZE WORK-FIELDS.
PERFORM
VARYING IX
FROM 1
BY 1
UNTIL IX GREATER THAN PASSED-SIZE

MOVE PASSED-ISBN (IX:1) TO WF-DIGIT
IF WF-DIGIT IS NUMERIC
IF WEIGHT-1
ELSE
COMPUTE WF-SUM = WF-SUM +
(NUMVAL(WF-DIGIT) * 3)
END-COMPUTE
END-IF
END-IF

END-PERFORM.

IF MOD(WF-SUM, 10) = 0
MOVE +0 TO RETURN-VALUE
ELSE
MOVE -1 TO RETURN-VALUE
END-IF.

GOBACK.
* - - - - - - - - - - - - - - - - - - - - - - PROGRAM EXIT POINT

END FUNCTION validISBN13.
```
Output:
```978-1734314502   (good)
978-1788399081   (good)
```

## Cowgol

```include "cowgol.coh";

sub check_isbn13(isbn: [uint8]): (r: uint8) is
var n: uint8 := 0;
r := 0;
loop
var c := [isbn];
isbn := @next isbn;
if c == 0 then break; end if;
c := c - '0';
if c <= 9 then
r := r + c;
n := n + 1;
if (n & 1) == 0 then
r := r + c * 2;
end if;
end if;
end loop;
if n == 13 and r%10 == 0 then
r := 1;
else
r := 0;
end if;
end sub;

var isbns: [uint8][] := {
"978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083"
};

var result: [uint8][] := {": bad\n", ": good\n"};

var n: uint8 := 0;
while n < @sizeof isbns loop
print(isbns[n]);
print(result[check_isbn13(isbns[n])]);
n := n + 1;
end loop;```
Output:
```978-1734314502: good
978-1788399081: good

## D

Translation of: Kotlin
```import std.stdio;

bool isValidISBN13(string text) {
int sum, i;
foreach (c; text) {
if ('0' <= c && c <= '9') {
int value = c - '0';
if (i % 2 == 0) {
sum += value;
} else {
sum += 3 * value;
}

i++;
}
}
return i == 13 && 0 == sum % 10;
}

unittest {
assert(isValidISBN13("978-1734314502"));
assert(!isValidISBN13("978-1734314509"));
assert(isValidISBN13("978-1788399081"));
assert(!isValidISBN13("978-1788399083"));
}
```

## Delphi

Works with: Delphi version 6.0

```function ValidateISBN(ISBN: string): boolean;
{Validate an ISBN number}
var I,N,Sum: integer;
begin
Sum:=0;
{Go througha chars, ignoring non-digits}
for I:=1 to Length(ISBN) do
if ISBN[I] in ['0'..'9'] then
begin
N:=StrToInt(ISBN[I]);
{Every other digit multiplied by 3}
if (I and 1)=1 then N:=N*3;
{Sum digits}
Sum:=Sum+N;
end;
{The sum must be an even multiple of 10}
Result:=(Sum mod 10)=0;
end;

procedure ValidateAndShow(Memo: TMemo; ISBN: string);
{Validate ISBN number and show the result}
var S: string;
begin
S:=ISBN;
if ValidateISBN(ISBN) then S:=S+' (Good)'
end;

procedure TestISBNSet(Memo: TMemo);
{Test supplied set of ISBN numbers}
begin
ValidateAndShow(Memo,'978-0596528126');		//(good)
ValidateAndShow(Memo,'978-1788399081');		//(good)
end;
```
Output:
```978-0596528126 (Good)
978-1788399081 (Good)

```

## Draco

```proc nonrec isbn13_check(*char isbn) bool:
byte n, check, d;
char cur;
bool ok;
n := 0;
check := 0;
ok := true;
while
cur := isbn*;
isbn := isbn + 1;
ok and cur ~= '\e'
do
if n=3 then
if cur ~= '-' then ok := false fi
elif cur<'0' or cur>'9' then
ok := false
else
d := cur - '0';
if n=1 or (n>3 and n&1 = 0) then
d := d * 3;
fi;
check := check + d
fi;
n := n + 1
od;
ok and n = 14 and check%10 = 0
corp

proc nonrec test(*char isbn) void:
writeln(isbn, ": ",
if isbn13_check(isbn) then "good" else "bad" fi)
corp

proc nonrec main() void:
test("978-1734314502");
test("978-1734314509");
test("978-1788399081");
test("978-1788399083")
corp```
Output:
```978-1734314502: good
978-1788399081: good

## EasyLang

```func ISBN13check isbn\$ .
for c\$ in strchars isbn\$
if c\$ <> "-"
ndigs += 1
.
dig = number c\$
if ndigs mod 2 = 0
dig *= 3
.
sum += dig
.
if sum mod 10 <> 0
return 0
.
return 1
.
codes\$[] = [ "978-0596528126" "978-0596528120" "978-1788399081" "978-1788399083" ]
for code\$ in codes\$[]
if ISBN13check code\$ = 1
print code\$ & " is a valid ISBN"
else
print code\$ & " is not a valid ISBN"
.
.
```
Output:
```978-0596528126 is a valid ISBN
978-0596528120 is not a valid ISBN
978-1788399081 is a valid ISBN
978-1788399083 is not a valid ISBN
```

## Excel

### LAMBDA

Binding the name ISBN13Check to the following lambda expression in the Name Manager of the Excel WorkBook:

```ISBN13Check
=LAMBDA(s,
LET(
ns, FILTERP(
LAMBDA(v,
NOT(ISERROR(v))
)
)(
VALUE(CHARSROW(s))
),
ixs, SEQUENCE(
1, COLUMNS(ns),
1, 1
),

0 = MOD(
SUM(
IF(0 <> MOD(ixs, 2),
INDEX(ns, ixs),
3 * INDEX(ns, ixs)
)
),
10
)
)
)
```

and also assuming the following generic bindings in the Name Manager for the WorkBook:

```CHARSROW
=LAMBDA(s,
MID(s,
SEQUENCE(1, LEN(s), 1, 1),
1
)
)

FILTERP
=LAMBDA(p,
LAMBDA(xs,
FILTER(xs, p(xs))
)
)

ISDIGIT
=LAMBDA(c,
LET(
ic, CODE(c),

AND(47 < ic, 58 > ic)
)
)
```
Output:
 =ISBN13Check(A2) fx A B 1 Candidate string ISBN13 checked 2 978-1734314502 TRUE 3 978-1734314509 FALSE 4 978-1788399081 TRUE 5 978-1788399083 FALSE

## Factor

```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-1788399081: good
```

## Forth

The following word not only identifies correct 13 digit ISBN (and EAN) codes, but also 8 digit EAN and GTIN codes.

```: is-digit [char] 0 - 10 u< ;

: isbn?                                ( a n -- f)
1- chars over + 2>r 0 1 2r> ?do
dup i c@ dup is-digit              \ get length and factor, setup loop
if [char] 0 - * rot + swap 3 * 8 mod else drop drop then
-1 chars +loop drop 10 mod 0=        \ now calculate checksum
;
```
Output:

In Forth, a "true" value is indicated by "-1".

```s" 978-1734314502" isbn? .  -1  ok
s" 978-1734314509" isbn? .  0  ok
s" 978-1788399081" isbn? .  -1  ok
s" 978-1788399083" isbn? .  0  ok
```

## Fortran

```program isbn13
implicit none

character(len=14), dimension(4), parameter  :: isbns=["978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083"]
integer                                     :: i

do i = 1, ubound(isbns, 1)
if (check_isbn13(isbns(i))) then
print*, isbns(i), " : ", "good"
else
print*, isbns(i), " : ", "bad"
end if
end do
contains
pure function check_isbn13(isbn)
character(len=*), intent(in)    :: isbn
logical                         :: check_isbn13
integer                         :: summ, counter, i, digit

check_isbn13 = .false.
counter = 0
summ = 0

do i = 1, len(isbn)
if (isbn(i:i) == ' ' .or. isbn(i:i) == '-') cycle
counter = counter + 1
if (modulo(counter, 2) == 0) then
summ = summ + 3*digit
else
summ = summ + digit
end if
end do
if (counter == 13 .and. modulo(summ, 10) == 0) check_isbn13 = .true.
end function check_isbn13
end program isbn13
```
Output:
``` 978-1734314502 : good
978-1788399081 : good
```

## FreeBASIC

```#define ZEROC asc("0")

function is_num( byval c as string ) as boolean
if asc(c) >= ZEROC andalso asc(c)<ZEROC+10 then return true
return false
end function

function is_good_isbn( isbn as string ) as boolean
dim as uinteger charno = 0, digitno = 0, sum = 0
dim as string*1 currchar
while charno <= len(isbn)
currchar = mid(isbn,charno,1)
if is_num(currchar) then
if digitno mod 2 = 1 then
sum += 2*(asc(currchar)-ZEROC)
end if
sum += asc(currchar)-ZEROC
digitno += 1
end if
charno += 1
wend
if sum mod 10 = 0 then
return true
else
return false
end if
end function

dim as string isbns(0 to 3) = { "978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083" }
dim as uinteger i
for i = 0 to 3
if is_good_isbn( isbns(i) ) then
print isbns(i)+": good"
else
end if
next i```
Output:
```978-1734314502: good
978-1788399081: good
```

## F#

```// ISBN13 Check Digit
open System

let parseInput (input: string) =
Seq.map(fun c -> c |> string) input |> Seq.toList |> List.map(fun x -> Int32.Parse x)

[<EntryPoint>]
let main argv =
let isbnnum = parseInput (String.filter (fun x -> x <> '-') argv.[0])
// Multiply every other digit by 3
let everyOther = List.mapi (fun i x -> if i % 2 = 0 then x * 3 else x) isbnnum
// Sum the *3 list with the original list
let sum = List.sum everyOther + List.sum isbnnum
// If the remainder of sum / 10 is 0 then it's a valid ISBN13
if sum % 10 = 0 then
printfn "%s Valid ISBN13" argv.[0]
else
printfn "%s Invalid ISBN13" argv.[0]
0
```
Output:
```978-1734314502 Valid ISBN13
978-1734314509 Inalid ISBN13
978-1788399081 Valid ISBN13
978-1788399083 Inalid ISBN13```

## Fōrmulæ

Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.

Programs in Fōrmulæ are created/edited online in its website.

In this page you can see and run the program(s) related to this task and their results. You can also change either the programs or the parameters they are called with, for experimentation, but remember that these programs were created with the main purpose of showing a clear solution of the task, and they generally lack any kind of validation.

Solution

Test cases

## Gambas

Translation of: BASIC256
```Public Sub Main()

Dim isbn As String[] = ["978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083", "978-2-74839-908-0", "978-2-74839-908-5", "978 1 86197 876 9"]

For n As Integer = 1 To isbn.Count
Dim sum As Integer = 0, num As Integer
Dim isbnStr As String = isbn[n]
isbnStr = Replace(isbnStr, "-", "")
isbnStr = Replace(isbnStr, " ", "")
For m As Integer = 1 To Len(isbnStr)
If m Mod 2 = 0 Then
num = 3 * CInt(Mid(isbnStr, m, 1))
Else
num = CInt(Mid(isbnStr, m, 1))
End If
sum += num
Next
If sum Mod 10 = 0 Then
Print isbn[n]; ": good"
Else
End If
Next

End
```

## Go

```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 {
if checkIsbn13(isbn) {
res = "good"
}
fmt.Printf("%s: %s\n", isbn, res)
}
}
```
Output:
```978-1734314502: good
978-1788399081: good
```

```import Data.Char (digitToInt, isDigit)
import Text.Printf (printf)

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 = sum . map (\(x, y) -> x + y * 3) . pair . digits

main :: IO ()
main =
mapM_
(printf "%s: Valid: %s\n" <*> (show . validIsbn13))
[ "978-1734314502",
"978-1734314509",
"978-1788399081",
"978-1788399083"
]
```
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)```

## IS-BASIC

```100 PROGRAM "ISBN13.bas"
110 DO
120   PRINT :INPUT PROMPT "ISBN-13 code: ":IS\$
130   IF IS\$="" THEN EXIT DO
140   IF ISBN(IS\$) THEN
150     PRINT "Ok."
160   ELSE
170     PRINT "CRC error."
180   END IF
190 LOOP
200 DEF TRIM\$(S\$)
210   LET T\$=""
220   FOR I=1 TO LEN(S\$)
230     IF S\$(I)>CHR\$(47) AND S\$(I)<CHR\$(58) THEN LET T\$=T\$&S\$(I)
240   NEXT
250   LET TRIM\$=T\$
260 END DEF
270 DEF ISBN(S\$)
280   LET SUM,ISBN=0:LET ISBN\$=TRIM\$(IS\$)
290   IF LEN(ISBN\$)<>13 THEN PRINT "Invalid length.":EXIT DEF
300   FOR I=1 TO 11 STEP 2
310     LET SUM=SUM+VAL(ISBN\$(I))+VAL(ISBN\$(I+1))*3
320   NEXT
330   LET SUM=SUM+VAL(ISBN\$(13))
340   IF MOD(SUM,10)=0 THEN LET ISBN=-1
350 END DEF```

## J

```   D            =:  '0123456789'

isbn13c      =:  D&([ check@:i. clean)
check      =:  0 = 10 | lc
lc       =:  [ +/@:* weight
weight =:  1 3 \$~ #
clean      =:  ] -. a. -. [
```
Output:
```   isbn13c;._1 ' 978-1734314502 978-1734314509 978-1788399081 978-1788399083'
1 0 1 0
```

## Java

```public static void main(String[] args) {
String[] isbn13s = {
"978-0596528126",
"978-0596528120",
"978-1788399081",
"978-1788399083"
};
for (String isbn13 : isbn13s)
System.out.printf("%s %b%n", isbn13, validateISBN13(isbn13));
}

static boolean validateISBN13(String string) {
int[] digits = digits(string.strip().replace("-", ""));
return digits[12] == checksum(digits);
}

static int[] digits(String string) {
int[] digits = new int[13];
int index = 0;
for (char character : string.toCharArray()) {
if (character < '0' || character > '9')
throw new IllegalArgumentException("Invalid ISBN-13");
/* convert ascii to integer */
digits[index++] = Character.digit(character, 10);
}
return digits;
}

static int checksum(int[] digits) {
int total = 0;
int index = 0;
for (int digit : digits) {
if (index == 12) break;
if (index++ % 2 == 1) digit *= 3;
total += digit;
}
return 10 - (total % 10);
}
```
```978-0596528126 true
978-0596528120 false
978-1788399081 true
978-1788399083 false
```

An alternate demonstration

```public static void main(){
System.out.println(isISBN13("978-1734314502"));
System.out.println(isISBN13("978-1734314509"));
System.out.println(isISBN13("978-1788399081"));
System.out.println(isISBN13("978-1788399083"));
}
public static boolean isISBN13(String in){
int pre = Integer.parseInt(in.substring(0,3));
if (pre!=978)return false;
String postStr = in.substring(4);
if (postStr.length()!=10)return false;
int post = Integer.parseInt(postStr);
int sum = 38;
for(int x = 0; x<10;x+=2)
sum += (postStr.charAt(x)-48)*3 + ((postStr.charAt(x+1)-48));
if(sum%10==0) return true;
return false;
}
```
Output:
```true
false
true
false
```

## jq

Works with: jq

Works with gojq, the Go implementation of jq

```def isbn_check:
def digits: tostring | explode | map( select(. >= 48 and . <= 57) | [.] | implode | tonumber);
def sum(s): reduce s as \$x (null; . + \$x);
digits
| . as \$digits
|      sum(range(0;length;2) | \$digits[.]) as \$one
| (3 * sum(range(1;length;2) | \$digits[.])) as \$two
| ((\$one+\$two) % 10) == 0;

def testingcodes:
["978-1734314502", "978-1734314509",
"978-1788399081", "978-1788399083"];

testingcodes[]
| "\(.): \(if isbn_check then "good" else "bad" end)"```
Output:
```978-1734314502: good
978-1788399081: good
```

## Julia

```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-1788399081: good
```

## K

Works with: ngn/k
```digits: {x[&(x>"/")&x<":"]-"0"}
isbn13c: 0=10!+/{x*(#x)#1 3} digits@

isbn13c "978-0596528126"
1
isbn13c "978-0596528120"
0
isbn13c " 978-1788399081"
1
isbn13c "978-1788399083"
0
```

## Kotlin

```fun isValidISBN13(text: String): Boolean {
val isbn = text.replace(Regex("[- ]"), "")
return isbn.length == 13 && isbn.map { it - '0' }
.mapIndexed { index, value -> when (index % 2) { 0 -> value else -> 3 * value } }
.sum() % 10 == 0
}
```

Tested using Spek

```describe("ISBN Utilities") {
mapOf(
"978-1734314502" to true,
"978-1734314509" to false,
"978-1788399081" to true,
"978-1788399083" to false
).forEach { (input, expected) ->
it("returns \$expected for \$input") {
println("\$input: \${when(isValidISBN13(input)) {
true -> "good"
}}")
assert(isValidISBN13(input) == expected)
}
}
}
```
Output:
```978-1734314502: good
978-1788399081: good
```

## langur

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-0596528126": true,
"978-0596528120": 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-0596528126": true,
"978-0596528120": 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-0596528126: good
978-1788399081: good

## Lua

Translation of: C
```function checkIsbn13(isbn)
local count = 0
local sum = 0
for c in isbn:gmatch"." do
if c == ' ' or c == '-' then
-- skip
elseif c < '0' or '9' < c then
return false
else
local digit = c - '0'
if (count % 2) > 0 then
sum = sum + 3 * digit
else
sum = sum + digit
end
count = count + 1
end
end

if count ~= 13 then
return false
end
return (sum % 10) == 0
end

function test(isbn)
if checkIsbn13(isbn) then
print(isbn .. ": good")
else
end
end

function main()
test("978-1734314502")
test("978-1734314509")
test("978-1788399081")
test("978-1788399083")
end

main()
```
Output:
```978-1734314502: good
978-1788399081: good

## Mathematica / Wolfram Language

```ClearAll[ValidISBNQ]
ValidISBNQ[iban_String] := Module[{i},
i = StringReplace[iban, {" " -> "", "-" -> ""}];
If[StringMatchQ[i, Repeated[DigitCharacter]],
i = ToExpression /@ Characters[i];
i[[2 ;; ;; 2]] *= 3;
Mod[Total[i], 10] == 0
,
False
]
]
ValidISBNQ["978-1734314502"]
ValidISBNQ["978-1734314509"]
ValidISBNQ["978-1788399081"]
ValidISBNQ["978-1788399083"]
```
Output:
```True
False
True
False```

## MiniScript

This GUI implementation is for use with Mini Micro.

```isISBN13 = function(n)
n = n.replace("-","").replace(" ","")
s = 0
for i in range(0, n.len-1,2)
s += n[i].val
end for
for i in range(1, n.len-1,2)
s += n[i].val * 3
end for
return not (s % 10)
end function

testValues = "978-0596528126 978-0596528120 978-1788399081 978-1788399083".split(" ")
for val in testValues
print val + " " + ["bad", "good"][isISBN13(val)]
end for
```
Output:
```978-0596528126 good
978-1788399081 good

## Modula-2

```MODULE ISBN;
FROM InOut IMPORT WriteString, WriteLn;
FROM Strings IMPORT Length;

PROCEDURE validISBN(s: ARRAY OF CHAR): BOOLEAN;
VAR total, i, length: CARDINAL;
BEGIN
total := 0;
length := Length(s);
IF (length # 14) OR (s[3] # '-') THEN
RETURN FALSE;
END;
FOR i := 0 TO length-1 DO
IF i # 3 THEN
IF (s[i] < '0') OR (s[i] > '9') THEN
RETURN FALSE;
ELSIF (i < 3) AND (i MOD 2 = 1) OR (i > 3) AND (i MOD 2 = 0) THEN
total := total + 3 * (ORD(s[i]) - ORD('0'));
ELSE
total := total + ORD(s[i]) - ORD('0');
END;
END;
END;
END validISBN;

PROCEDURE check(s: ARRAY OF CHAR);
BEGIN
WriteString(s);
WriteString(': ');
IF validISBN(s) THEN
WriteString('good');
ELSE
END;
WriteLn;
END check;

BEGIN
check('978-1734314502');
check('978-1734314509');
check('978-1788399081');
check('978-1788399083');
END ISBN.
```
Output:
```978-1734314502: good
978-1788399081: good

## Nanoquery

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
if checkIsbn13(isbn)
res = "good"
end

print format("%s: %s\n", isbn, res)
end```
Output:
```978-1734314502: good
978-1788399081: good

## Nim

```import strutils, strformat

func is_isbn*(s: string): bool =
var sum, len: int
for c in s:
if is_digit(c):
sum += (ord(c) - ord('0')) * (if len mod 2 == 0: 1 else: 3)
len += 1
elif c != ' ' and c != '-':
return false
return (len == 13) and (sum mod 10 == 0)

when is_main_module:
let isbns = [ "978-1734314502", "978-1734314509",
"978-1788399081", "978-1788399083" ]
for isbn in isbns:
var quality: string = if is_isbn(isbn): "good" else: "bad"
echo &"{isbn}: {quality}"
```
Output:
```978-1734314502: good
978-1788399081: good
```

## Pascal

Works with: Extended Pascal
```program ISBNChecksum(output);

const
codeIndexMaximum = 17;
ISBNIndexMinimum = 1;
ISBNIndexMaximum = 13;
ISBNIndexRange = ISBNIndexMaximum - ISBNIndexMinimum + 1;

type
code = string(codeIndexMaximum);
codeIndex = 1..codeIndexMaximum value 1;
decimalDigit = '0'..'9';
decimalValue = 0..9;
ISBNIndex = ISBNIndexMinimum..ISBNIndexMaximum;
ISBN = array[ISBNIndex] of decimalDigit;

{ returns the integer value represented by a character }
function numericValue(protected c: decimalDigit): decimalValue;
begin
{ in Pascal result variable bears the same name as the function }
numericValue := ord(c) - ord('0')
end;

{ determines whether an ISBN is technically valid (checksum correct) }
function isValidISBN(protected n: ISBN): Boolean;
var
sum: 0..225 value 0;
i: ISBNIndex;
begin
{ NB: in Pascal for-loop-limits are _inclusive_ }
for i := ISBNIndexMinimum to ISBNIndexMaximum do
begin
{ alternating scale factor 3^0, 3^1 based on Boolean }
sum := sum + numericValue(n[i]) * 3 pow ord(not odd(i))
end;

isValidISBN := sum mod 10 = 0
end;

{ transform '978-0-387-97649-5' into '9780387976495' }
function digits(n: code): code;
var
sourceIndex, destinationIndex: codeIndex;
begin
for sourceIndex := 1 to length(n) do
begin
if n[sourceIndex] in ['0'..'9'] then
begin
n[destinationIndex] := n[sourceIndex];
destinationIndex := destinationIndex + 1
end
end;

{ to alter a string’s length you need overwrite it completely }
digits := subStr(n, 1, destinationIndex - 1)
end;

{ data type coercion }
function asISBN(protected n: code): ISBN;
var
result: ISBN;
begin
unpack(n[1..length(n)], result, 1);
asISBN := result
end;

{ tells whether a string value contains a proper ISBN representation }
function isValidISBNString(protected hyphenatedForm: code): Boolean;
var
digitOnlyForm: code;
begin
digitOnlyForm := digits(hyphenatedForm);
{ The Extended Pascal `and_then` Boolean operator allows us }
{ to first check the length before invoking `isValidISBN`. }
isValidISBNString := (length(digitOnlyForm) = ISBNIndexRange)
and_then isValidISBN(asISBN(digitOnlyForm))
end;

{ === MAIN ============================================================= }
begin
writeLn(isValidISBNString('978-1734314502'));
writeLn(isValidISBNString('978-1734314509'));
writeLn(isValidISBNString('978-1788399081'));
writeLn(isValidISBNString('978-1788399083'))
end.
```
Output:
```True
False
True
False```

## Perl

```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

```with javascript_semantics
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-1788399081: good
978-2-74839-908-0: good
978 1 86197 876 9: good
```

## PicoLisp

```(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
```

## PL/M

```100H:

CHECK\$ISBN13: PROCEDURE (PTR) BYTE;
DECLARE PTR ADDRESS, ISBN BASED PTR BYTE;
DECLARE (I, F, T) BYTE;
F = 1;
T = 0;
DO I = 0 TO 13;
IF I = 3 THEN DO;
/* THIRD CHAR SHOULD BE '-' */
IF ISBN(I) <> '-' THEN RETURN 0;
END;
ELSE DO;
/* DIGITS MUST BE VALID */
IF ISBN(I) < '0' OR ISBN(I) > '9' THEN RETURN 0;
T = T + (ISBN(I) - '0') * F;
F = 4 - F; /* MULTIPLY BY 1 AND 3 ALTERNATELY */
END;
END;
RETURN (T MOD 10) = 0;
END CHECK\$ISBN13;

/* CP/M BDOS CALL */
BDOS: PROCEDURE (FUNC, ARG);
GO TO 5;
END BDOS;

PRINT: PROCEDURE (STR);
CALL BDOS(9, STR);
END PRINT;

/* TESTS */
TEST(0) = .'978-1734314502\$';
TEST(1) = .'978-1734314509\$';
TEST(2) = .'978-1788399081\$';
TEST(3) = .'978-1788399083\$';

DECLARE I BYTE;
DO I = 0 TO LAST(TEST);
CALL PRINT(TEST(I));
CALL PRINT(.': \$');
IF CHECK\$ISBN13(TEST(I)) THEN
CALL PRINT(.'GOOD\$');
ELSE
CALL PRINT(.(13,10,'\$'));
END;

CALL BDOS(0,0);
EOF```
Output:
```978-1734314502: GOOD
978-1788399081: GOOD

## PowerShell

```function Get-ISBN13 {
\$codes = (
"978-1734314502",
"978-1734314509",
"978-1788399081",
"978-1788399083"
)

foreach (\$line in \$codes) {

\$sum = \$null
\$codeNoDash = \$line.Replace("-","")

for (\$i = 0; \$i -lt \$codeNoDash.length; \$i++) {

if ((\$i % 2) -eq 1) {

\$sum += [decimal]\$codeNoDash[\$i] * 3

}else {

\$sum += [decimal]\$codeNoDash[\$i]

}
}

if ((\$sum % 10) -eq 0) {

Write-Host "\$line Good"

}else {

}
}
}
Get-ISBN13
```
Output:
```978-1734314502 Good
978-1788399081 Good
```

## PureBasic

```Macro TestISBN13(X)
Print(X)
If IsISBN13(X) : PrintN(" good") : Else : PrintN(" bad") : EndIf
EndMacro

Procedure.b IsISBN13(ISBN13.s)
ISBN13=Left(ISBN13,3)+Mid(ISBN13,5)
If IsNAN(Val(ISBN13)) Or Len(ISBN13)<>13 : ProcedureReturn #False : EndIf
Dim ISBN.s{1}(12) : PokeS(@ISBN(),ISBN13)
For i=0 To 11 Step 2 : sum+Val(ISBN(i))+Val(ISBN(i+1))*3 : Next
sum+Val(ISBN(12))
ProcedureReturn Bool(sum%10=0)
EndProcedure

If OpenConsole()
TestISBN13("978-1734314502")
TestISBN13("978-1734314509")
TestISBN13("978-1788399081")
TestISBN13("978-1788399083")
Input()
EndIf```
Output:
```978-1734314502 good
978-1788399081 good
```

## Python

```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

# isISBN13 :: String -> Bool
def isISBN13(s):
'''True if s is a valid ISBN13 string
'''
digits = [int(c) for c in s if c.isdigit()]
return 13 == len(digits) and (
0 == sum(map(
lambda f, x: f(x),
cycle([
lambda x: x,
lambda x: 3 * x
]),
digits
)) % 10
)

# ------------------------- TEST -------------------------
# main :: IO ()
def main():
'''Test strings for ISBN-13 validity.'''

print('\n'.join(
repr((s, isISBN13(s))) for s
in ["978-1734314502",
"978-1734314509",
"978-1788399081",
"978-1788399083"
]
))

# MAIN ---
if __name__ == '__main__':
main()
```
Output:
```('978-1734314502', True)
('978-1734314509', False)
('978-1788399081', True)
('978-1788399083', False)```

## Quackery

```[ char 0 char 9 1+ within ]  is digit?    ( c --> b )

[ 1 & ]                      is odd?      ( n --> b )

[ [] swap ]'[ swap
witheach [
dup nested
unrot over do
iff [ dip join ]
else nip
] drop ]                   is filter    ( [ --> [ )

[ 0 swap
witheach [
char->n i^ odd?
iff [ 3 * + ]
else +
] ]                        is checksum  ( \$ --> n )

[ filter digit?
dup size 13 = not
iff [ drop false ] done
checksum 10 mod 0 = ]      is isbn      ( \$ --> b )

[ dup echo\$ say ": " isbn
iff [ say "Good" ]
else [ say "Bad" ] cr ]    is isbn-test ( \$ -->   )

\$ '978-1734314502' isbn-test
\$ '978-1734314509' isbn-test
\$ '978-1788399081' isbn-test
\$ '978-1788399083' isbn-test```
Output:
```978-1734314502: Good
978-1788399081: Good
```

## Racket

```#lang racket/base

(define (isbn13-check-digit-valid? s)
(zero? (modulo (for/sum ((i (in-naturals))
(d (regexp-replace* #px"[^[:digit:]]" s "")))
(* (- (char->integer d) (char->integer #\0))
(if (even? i) 1 3)))
10)))

(module+ test
(require rackunit)
(check-true (isbn13-check-digit-valid? "978-1734314502"))
(check-false (isbn13-check-digit-valid? "978-1734314509"))
(check-true (isbn13-check-digit-valid? "978-1788399081"))
(check-false (isbn13-check-digit-valid? "978-1788399083")))
```
Output:

no output indicates tests pass

## Raku

(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
```

## Red

```check_valid_isbn13: function [str] [
is_digit: charset [#"0" - #"9"]
remove-each i str [not pick is_digit i] ; remove non-digits

either 13 = length? str [               ; reject strings of incorrect length
sum: 0
repeat i 13 [
mul: either even? i [3] [1]         ; multiplier for odd/even digits
sum: sum + (mul * to integer! to string! pick str i)
]

zero? (sum % 10)                      ; check if remainder mod 10 is zero
] [
false
]
]

; check given examples
foreach [str] ["978-1734314502" "978-1734314509" "978-1788399081" "978-1788399083"] [
prin str
prin " - "
print check_valid_isbn13 str
]
```
Output:
```978-1734314502 - true
978-1734314509 - false
978-1788399081 - true
978-1788399083 - false
```

## REXX

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.
```

## Ring

```load "stdlib.ring"

isbn = ["978-1734314502","978-1734314509", "978-1788399081", "978-1788399083","978-2-74839-908-0","978-2-74839-908-5","978 1 86197 876 9"]

for n = 1 to len(isbn)
sum = 0
isbnStr = isbn[n]
isbnStr = substr(isbnStr,"-","")
isbnStr = substr(isbnStr," ","")
for m = 1 to len(isbnStr)
if m%2 = 0
num = 3*number(substr(isbnStr,m,1))
sum = sum + num
else
num = number(substr(isbnStr,m,1))
sum = sum + num
ok
next
if sum%10 = 0
see "" + isbn[n] + ": true" + nl
else
see "" + isbn[n] + ": bad" + nl
ok
next```

Output:

```978-1734314502: true
978-1788399081: true
978-2-74839-908-0: true
978 1 86197 876 9: true
```

## RPL

Works with: Halcyon Calc version 4.2.7
```≪ → isbn
≪ 0 1 CF
1 isbn SIZE FOR j
IF "0123456789" isbn j DUP SUB POS THEN
LAST 1 -
IF 1 FS?C THEN 3 * ELSE 1 SF END
+
END
NEXT
≫
10 MOD NOT
≫
'ISBN?' STO
```
```≪ { "978-0596528126" "978-0596528120" "978-1788399081" "978-1788399083" } → tests
≪ 1 tests SIZE FOR j tests  GET ISBN? NEXT ≫
≫ EVAL
```
Output:
```4: 1
3: 0
2: 1
1: 0
```

## Ruby

```def validISBN13?(str)
cleaned = str.delete("^0-9").chars
return false unless cleaned.size == 13
cleaned.each_slice(2).sum{|d1, d2| d1.to_i + 3*d2.to_i }.remainder(10) == 0
end

isbns = ["978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083"]
isbns.each{|isbn| puts "#{isbn}: #{validISBN13?(isbn)}" }
```
Output:
```978-1734314502: true
978-1734314509: false
978-1788399081: true
978-1788399083: false
```

## Rust

```fn main() {
let isbns = ["978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083"];
isbns.iter().for_each(|isbn| println!("{}: {}", isbn, check_isbn(isbn)));
}

fn check_isbn(isbn: &str) -> bool {
if isbn.chars().filter(|c| c.is_digit(10)).count() != 13 {
return false;
}
let checksum = isbn.chars().filter_map(|c| c.to_digit(10))
.zip([1, 3].iter().cycle())
.fold(0, |acc, (val, fac)| acc + val * fac);
checksum % 10 == 0
}
```
Output:
```978-1734314502: true
978-1734314509: false
978-1788399081: true
978-1788399083: false
```

## Seed7

```\$ include "seed7_05.s7i";

const func boolean: isISBN13 (in var string: input) is func
result
var boolean: isbn is FALSE;
local
var char: c is ' ';
var integer: digit is 0;
var integer: i is 1;
var integer: sum is 0;
begin
input := replace(input, " ", "");
input := replace(input, "-", "");
if length(input) = 13 then
for c range input do
digit := ord(c) - 48;
if not odd(i) then
digit *:= 3;
end if;
sum +:= digit;
incr(i);
end for;
isbn := sum rem 10 = 0;
end if;
end func;

const proc: main is func
local
var string: str is "";
begin
for str range [] ("978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083") do
writeln(str <& ": " <& isISBN13(str));
end for;
end func;```
Output:
```978-1734314502: TRUE
978-1734314509: FALSE
978-1788399081: TRUE
978-1788399083: FALSE
```

## Standard ML

```local
fun check (c, p as (m, n)) =
if Char.isDigit c then
(not m, (if m then 3 * (ord c - 48) else ord c - 48) + n)
else
p
in
fun checkISBN s =
Int.rem (#2 (CharVector.foldl check (false, 0) s), 10) = 0
end

val test = ["978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083"]
val () = (print
o concat
o map (fn s => s ^ (if checkISBN s then ": good\n" else ": bad\n"))) test
```
Output:
```978-1734314502: good
978-1788399081: good

## Swift

```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-1788399081 => good

## Tcl

```proc validISBN13 code {
regsub -all {\D} \$code "" code ;# remove non-digits
if {[string length \$code] == 13} {
set sum 0
set fac 1
foreach digit [split \$code ""] {
set sum [expr {\$sum + \$digit * \$fac}]
set fac [expr {\$fac == 1? 3: 1}]
}
if {\$sum % 10 == 0} {return true}
}
return false
}
foreach test {
978-1734314502
978-1734314509
978-1788399081
978-1788399083
} {puts \$test:[validISBN13 \$test]}
```
Output:
```978-1734314502:true
978-1734314509:false
978-1788399081:true
978-1788399083:false```

Simpler variant, using two loop vars and constant factors; same output:

```proc validISBN13 code {
regsub -all {\D} \$code "" code ;# remove non-digits
if {[string length \$code] == 13} {
set sum 0
foreach {d1 d2} [split \$code ""] {
if {\$d2 eq ""} {set d2 0} ;# last round
set sum [expr {\$sum + \$d1 + \$d2 * 3}]
}
if {\$sum % 10 == 0} {return true}
}
return false
}
```

## uBasic/4tH

Works with: version 3.64.0
```a := "978-1734314502"
Print Show(a), Show (Iif (Func(_IsISBN (a)), "good", "bad"))

a := "978-1734314509"
Print Show(a), Show (Iif (Func(_IsISBN (a)), "good", "bad"))

a := "978-1788399081"
Print Show(a), Show (Iif (Func(_IsISBN (a)), "good", "bad"))

a := "978-1788399083"
Print Show(a), Show (Iif (Func(_IsISBN (a)), "good", "bad"))

End

_IsISBN
Param (1)
Local (4)

c@ = 0 : e@ = 1                      ' set sum and multiplier

For b@ = Len (a@) - 1 To 0 Step -1   ' scan string in reverse
d@ = Peek(a@, b@) - Ord ("0")      ' get character
If ((d@ < 0) + (d@ > 9)) = 0 Then c@ = c@ + (d@ * e@)
e@ = (e@ * 3) % 8                  ' evaluate character, change multiplier
Next

Return ((c@ % 10) = 0)                 ' modulus 10 must be zero
```
Output:
```978-1734314502  good
978-1788399081  good

0 OK, 0:339```

## UNIX Shell

Works with: Bourne Again Shell
```check_isbn13 () {
local i n t
n=\${1//[^0-9]/}
t=0
for ((i=0; i<\${#n}; ++i )); do
(( t += \${n:i:1}*(1 + ((i&1)<<1)) ))
done
(( 0 == t % 10 ))
}

for isbn in 978-1734314502 978-1734314509 978-1788399081 978-1788399083; do
printf '%s: ' "\$isbn"
if check_isbn13 "\$isbn"; then
printf '%s\n' OK
else
printf '%s\n' 'NOT OK'
fi
done
```
Output:
```978-1734314502: OK
978-1734314509: NOT OK
978-1788399081: OK
978-1788399083: NOT OK```

## Visual Basic .NET

Translation of: C#
```Module Module1

Function CheckISBN13(code As String) As Boolean
code = code.Replace("-", "").Replace(" ", "")
If code.Length <> 13 Then
Return False
End If
Dim sum = 0
For Each i_d In code.Select(Function(digit, index) (index, digit))
Dim index = i_d.index
Dim digit = i_d.digit
If Char.IsDigit(digit) Then
sum += (Asc(digit) - Asc("0")) * If(index Mod 2 = 0, 1, 3)
Else
Return False
End If
Next
Return sum Mod 10 = 0
End Function

Sub Main()
Console.WriteLine(CheckISBN13("978-1734314502"))
Console.WriteLine(CheckISBN13("978-1734314509"))
Console.WriteLine(CheckISBN13("978-1788399081"))
Console.WriteLine(CheckISBN13("978-1788399083"))
End Sub

End Module
```
Output:
```True
False
True
False```

## V (Vlang)

Translation of: Go
```fn check_isbn13(isbn13 string) bool {
// remove any hyphens or spaces
isbn := isbn13.replace('-','').replace(' ','')
// check length == 13
le := isbn.len
if le != 13 {
return false
}
// check only contains digits and calculate weighted sum
mut sum := 0
for i, c in isbn.split('') {
if c.int() < '0'.int() || c.int() > '9'.int() {
return false
}
if i%2 == 0 {
sum += c.int() - '0'.int()
} else {
sum += 3 * (c.int() - '0'.int())
}
}
return sum%10 == 0
}

fn main() {
isbns := ["978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083"]
for isbn in isbns {
if check_isbn13(isbn) {
res = "good"
}
println("\$isbn: \$res")
}
}```
Output:
```978-1734314502: good
978-1788399081: good
```

## Wren

```var isbn13 = Fn.new { |s|
var cps = s.codePoints
var digits = []
// extract digits
for (i in 0...cps.count) {
var c = cps[i]
if (c >= 48 && c <= 57) digits.add(c)
}
// do calcs
var sum = 0
for (i in 0...digits.count) {
var d = digits[i] - 48
sum = sum + ((i%2 == 0) ? d : 3 * d)
}
return sum % 10 == 0
}

var tests = ["978-1734314502", "978-1734314509", "978-1788399081", "978-1788399083"]
for (test in tests) {
System.print("%(test) -> %(isbn13.call(test) ? "good" : "bad")")
}```
Output:
```978-1734314502 -> good
978-1788399081 -> good
```

## XPL0

```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-1788399081: good
978-1-59327-220-3: good
```

## zkl

```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