Skip to content

Commit 4227cb7

Browse files
Add ISBN Verifier Exercise (#550)
1 parent e775e52 commit 4227cb7

File tree

13 files changed

+256
-0
lines changed

13 files changed

+256
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,14 @@
606606
"practices": [],
607607
"prerequisites": [],
608608
"difficulty": 3
609+
},
610+
{
611+
"slug": "isbn-verifier",
612+
"name": "ISBN Verifier",
613+
"uuid": "408f5d5d-00f7-4dcb-bf57-8b8576ae903a",
614+
"practices": [],
615+
"prerequisites": [],
616+
"difficulty": 3
609617
}
610618
]
611619
},
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Instructions
2+
3+
The [ISBN-10 verification process][isbn-verification] is used to validate book identification numbers.
4+
These normally contain dashes and look like: `3-598-21508-8`
5+
6+
## ISBN
7+
8+
The ISBN-10 format is 9 digits (0 to 9) plus one check character (either a digit or an X only).
9+
In the case the check character is an X, this represents the value '10'.
10+
These may be communicated with or without hyphens, and can be checked for their validity by the following formula:
11+
12+
```text
13+
(d₁ * 10 + d₂ * 9 + d₃ * 8 + d₄ * 7 + d₅ * 6 + d₆ * 5 + d₇ * 4 + d₈ * 3 + d₉ * 2 + d₁₀ * 1) mod 11 == 0
14+
```
15+
16+
If the result is 0, then it is a valid ISBN-10, otherwise it is invalid.
17+
18+
## Example
19+
20+
Let's take the ISBN-10 `3-598-21508-8`.
21+
We plug it in to the formula, and get:
22+
23+
```text
24+
(3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 == 0
25+
```
26+
27+
Since the result is 0, this proves that our ISBN is valid.
28+
29+
## Task
30+
31+
Given a string the program should check if the provided string is a valid ISBN-10.
32+
Putting this into place requires some thinking about preprocessing/parsing of the string prior to calculating the check digit for the ISBN.
33+
34+
The program should be able to verify ISBN-10 both with and without separating dashes.
35+
36+
## Caveats
37+
38+
Converting from strings to numbers can be tricky in certain languages.
39+
Now, it's even trickier since the check digit of an ISBN-10 may be 'X' (representing '10').
40+
For instance `3-598-21507-X` is a valid ISBN-10.
41+
42+
[isbn-verification]: https://en.wikipedia.org/wiki/International_Standard_Book_Number
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"authors": ["therealowenrees"],
3+
"files": {
4+
"solution": [
5+
"isbn_verifier.ml"
6+
],
7+
"test": [
8+
"test.ml"
9+
],
10+
"example": [
11+
".meta/example.ml"
12+
],
13+
"editor": [
14+
"isbn_verifier.mli"
15+
]
16+
},
17+
"blurb": "Check if a given string is a valid ISBN-10 number.",
18+
"source": "Converting a string into a number and some basic processing utilizing a relatable real world example.",
19+
"source_url": "https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digit_calculation"
20+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
let isValid s =
2+
let chars = List.init (String.length s) (String.get s) in
3+
4+
let is_digit c = c >= '0' && c <= '9' in
5+
6+
let rec aux chars acc count =
7+
match chars with
8+
| [] ->
9+
if count <> 10 then false
10+
else acc mod 11 = 0
11+
| c :: rest ->
12+
if c = '-' || c = ' ' then
13+
aux rest acc count
14+
else if count = 9 && c = 'X' then
15+
aux rest (acc + 10 * (count + 1)) (count + 1)
16+
else if is_digit c then
17+
let value = int_of_char c - int_of_char '0' in
18+
aux rest (acc + value * (count + 1)) (count + 1)
19+
else
20+
false
21+
in
22+
23+
aux chars 0 0
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[0caa3eac-d2e3-4c29-8df8-b188bc8c9292]
13+
description = "valid isbn"
14+
15+
[19f76b53-7c24-45f8-87b8-4604d0ccd248]
16+
description = "invalid isbn check digit"
17+
18+
[4164bfee-fb0a-4a1c-9f70-64c6a1903dcd]
19+
description = "valid isbn with a check digit of 10"
20+
21+
[3ed50db1-8982-4423-a993-93174a20825c]
22+
description = "check digit is a character other than X"
23+
24+
[9416f4a5-fe01-4b61-a07b-eb75892ef562]
25+
description = "invalid check digit in isbn is not treated as zero"
26+
27+
[c19ba0c4-014f-4dc3-a63f-ff9aefc9b5ec]
28+
description = "invalid character in isbn is not treated as zero"
29+
30+
[28025280-2c39-4092-9719-f3234b89c627]
31+
description = "X is only valid as a check digit"
32+
33+
[f6294e61-7e79-46b3-977b-f48789a4945b]
34+
description = "valid isbn without separating dashes"
35+
36+
[185ab99b-3a1b-45f3-aeec-b80d80b07f0b]
37+
description = "isbn without separating dashes and X as check digit"
38+
39+
[7725a837-ec8e-4528-a92a-d981dd8cf3e2]
40+
description = "isbn without check digit and dashes"
41+
42+
[47e4dfba-9c20-46ed-9958-4d3190630bdf]
43+
description = "too long isbn and no dashes"
44+
45+
[737f4e91-cbba-4175-95bf-ae630b41fb60]
46+
description = "too short isbn"
47+
48+
[5458a128-a9b6-4ff8-8afb-674e74567cef]
49+
description = "isbn without check digit"
50+
51+
[70b6ad83-d0a2-4ca7-a4d5-a9ab731800f7]
52+
description = "check digit of X should not be used for 0"
53+
54+
[94610459-55ab-4c35-9b93-ff6ea1a8e562]
55+
description = "empty isbn"
56+
57+
[7bff28d4-d770-48cc-80d6-b20b3a0fb46c]
58+
description = "input is 9 characters"
59+
60+
[ed6e8d1b-382c-4081-8326-8b772c581fec]
61+
description = "invalid characters are not ignored after checking length"
62+
63+
[daad3e58-ce00-4395-8a8e-e3eded1cdc86]
64+
description = "invalid characters are not ignored before checking length"
65+
66+
[fb5e48d8-7c03-4bfb-a088-b101df16fdc3]
67+
description = "input is too long but contains a valid isbn"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
default: clean test
2+
3+
test:
4+
dune runtest
5+
6+
clean:
7+
dune clean
8+
9+
.PHONY: clean

exercises/practice/isbn-verifier/dune

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
(executable
2+
(name test)
3+
(libraries base ounit2))
4+
5+
(alias
6+
(name runtest)
7+
(deps
8+
(:x test.exe))
9+
(action
10+
(run %{x})))
11+
12+
(alias
13+
(name buildtest)
14+
(deps
15+
(:x test.exe)))
16+
17+
(env
18+
(dev
19+
(flags
20+
(:standard -warn-error -A))))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
(lang dune 1.1)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
let isValid _ =
2+
failwith = "'isValid' is missing"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
val isValid : string -> bool

0 commit comments

Comments
 (0)