42 lines
977 B
Elixir
42 lines
977 B
Elixir
defmodule IsbnVerifier do
|
|
@doc """
|
|
Checks if a string is a valid ISBN-10 identifier
|
|
|
|
## Examples
|
|
|
|
iex> IsbnVerifier.isbn?("3-598-21507-X")
|
|
true
|
|
|
|
iex> IsbnVerifier.isbn?("3-598-2K507-0")
|
|
false
|
|
|
|
"""
|
|
|
|
@regex ~r/^(?<digits>\d{9})(?<check_digit>[0-9X])$/
|
|
|
|
@spec isbn?(String.t()) :: boolean
|
|
def isbn?(isbn) do
|
|
with isbn_without_dashes <- String.replace(isbn, "-", ""),
|
|
%{"digits" => digits, "check_digit" => check_digit} <-
|
|
Regex.named_captures(@regex, isbn_without_dashes) do
|
|
rem(check_sum(digits) + check_digit(check_digit), 11) == 0
|
|
else
|
|
_ -> false
|
|
end
|
|
end
|
|
|
|
defp check_sum(digits) do
|
|
{1, check_sum} =
|
|
digits
|
|
|> String.graphemes()
|
|
|> Enum.reduce({10, 0}, fn digit, {index, acc} ->
|
|
{index - 1, acc + String.to_integer(digit) * index}
|
|
end)
|
|
|
|
check_sum
|
|
end
|
|
|
|
defp check_digit("X"), do: 10
|
|
defp check_digit(string), do: String.to_integer(string)
|
|
end
|