ISBN13 check digit: Difference between revisions

Added OmniMark solution, which includes additional conditions to ignore non-ISBN-13 numbers
(Added OmniMark solution, which includes additional conditions to ignore non-ISBN-13 numbers)
 
(4 intermediate revisions by 2 users not shown)
Line 1,970:
=={{header|langur}}==
In this example, we map to multiple functions (actually 1 no-op).
<syntaxhighlight lang="langur">val .isbn13checkdigit = fn(var .s) {
val isbn13checkdigit = fn(var s) {
.s = replace(.s, RE/[\- ]/)
.s ->= rereplace(s, RE/^[0\-9 ]{13}$/ and)
s -> re/^[0-9]{13}$/ and
fold(fn{+}, map [_, fn{*3}], s2n .s) div 10
fold(fn{+}, map([_, fn{*3}], s2n(s))) div 10
}
 
val .tests = h{
"978-0596528126": true,
"978-0596528120": false,
Line 1,983 ⟶ 1,984:
}
 
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)")
}</syntaxhighlight>
 
In this example, we set a for loop value as it progresses.
<syntaxhighlight lang="langur">val .isbn13checkdigit = f(var .s) {
.s = replace(.s, RE/[\- ]/)
var .alt = true
.s -> re/^[0-9]{13}$/ and
for[=0] .d in s2n(.s) { _for += if(not= .alt: .d x 3; .d) } div 10
}
</syntaxhighlight>
 
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)")
}</syntaxhighlight>
 
{{out}}
Line 2,267 ⟶ 2,248:
978-1788399081: good
978-1788399083: bad
</pre>
 
=={{header|OmniMark}}==
<syntaxhighlight lang="omnimark">
define switch function isbn (value stream vs-s) as
local integer li-total initial {0}
local integer li-check
repeat scan vs-s
; Any digits in an ISBN-13 may be separated by a hyphen or space
match (digit => lpv-1 ('-' | space)? digit => lpv-3 ('-' | space)? ) => p
; Add the first digit to the total and add the second multiplied by 3
increment li-total by (lpv-1 + (lpv-3 * 3))
match any => lpv-c
; This is always the thirteenth digit, the 'check' digit
set li-check to lpv-c
again
do when 10 - li-total modulo 10 = li-check
return true
else when li-total modulo 10 = 0 and li-check = 0
return true
else
return false
done
 
process
; These are the first four test ISBN-13s from the problem description, with
; the first and third being valid and the second and fourth invalid.
submit "978-0596528126"
submit "978-0596528120"
submit "978-1788399081"
submit "978-1788399083"
 
; This ISBN-13 is from https://isbn-information.com/the-13-digit-isbn.html
submit "978-1-86197-876-9"
submit "978 1 86197 876 9"
 
; These ISBNs are from https://en.wikipedia.org/wiki/ISBN
submit "978-3-16-148410-0"
submit "978 3 16 148410 9" ; But this one has had the 'check' digit changed
submit "This is valid: 978-0-306-40615-7^" ; Adding some extra complexity :)
submit "978-03-0640-615 7." ; Formatted as "EAN-Group-Publisher-Title Check"
 
; These strings show how non-ISBN-13 numbers must be (and are) ignored.
submit "This is a 14-digit number - 555-30640610555 - so it is ignored.%n"
submit "This is an ISBN-10, so it is ignored too: 0-306-40615-2.%n"
 
; This find rule will only find a string that is an ISBN-13 (digit/-/space)
; combination. It has been split into three lines to make it easier to see
; what is being done.
; 1. The string must either be preceded by any character other than a digit
; or start the stream, and
; 2. It must then have 12 digits (with optional hyphens or spaces
; intermingled) and must conclude with a digit, and
; 3. It either must not be followed by a another digit (making it more
; than 13 digits, so not an ISBN-13) or the stream ends.
find ([any \ digit] | value-start) => lpv-s
((digit ('-' | space)?){12} digit) => lpv-n
([any \ digit] | value-end) => lpv-e
output lpv-s || lpv-n || lpv-e
do when isbn(lpv-n) = true
output ' (good)%n'
else
output ' (bad)%n'
done
 
; output all other characters verbatim
find any => lpv-char
output lpv-char
</syntaxhighlight>
 
{{out}}
<pre>
978-0596528126 (good)
978-0596528120 (bad)
978-1788399081 (good)
978-1788399083 (bad)
978-1-86197-876-9 (good)
978 1 86197 876 9 (good)
978-3-16-148410-0 (good)
978 3 16 148410 9 (bad)
This is valid: 978-0-306-40615-7^ (good)
978-03-0640-615 7. (good)
This is a 14-digit number - 555-30640610555 - so it is ignored.
This is an ISBN-10, so it is ignored too: 0-306-40615-2.
</pre>
 
Line 3,051 ⟶ 3,116:
 
=={{header|Standard ML}}==
===Easy to read version===
<syntaxhighlight lang="sml">local
<syntaxhighlight lang="sml">(* these type decorations are optional, you could just as well put:
fun isValidISBN s =
*)
fun isValidISBN (s : string) : bool =
let
val digits = List.filter Char.isDigit (explode s)
val nums = map (fn x => ord x - ord #"0") digits
val len = length nums
fun sumISBN [] = raise Domain
| sumISBN [x] = x
| sumISBN (x1::x2::xs) = x1 + 3*x2 + sumISBN xs
in
len = 13 andalso sumISBN nums mod 10 = 0
end
 
val test = ["978-1734314502", "978-1734314509",
"978-1788399081", "978-1788399083"]
 
fun printTest (s : string) : unit =
(print s; print (if isValidISBN s then ": good\n" else ": bad\n"))
 
fun main () = app printTest test</syntaxhighlight>
 
===Original version===
<syntaxhighlight lang="sml">let
fun check (c, p as (m, n)) =
if Char.isDigit c then
40

edits