Current section
Files
Jump to
Current section
Files
lib/signed_overpunch.ex
defmodule SignedOverpunch do
@error_message "invalid signed overpunch value: "
@moduledoc """
Module for converting a string in signed overpunch format into the
corresponding integer.
## Conversion Table:
| Code | Digit | Sign |
| ---- | ----- | ---- |
| } | 0 | − |
| J | 1 | − |
| K | 2 | − |
| L | 3 | − |
| M | 4 | − |
| N | 5 | − |
| O | 6 | − |
| P | 7 | − |
| Q | 8 | − |
| R | 9 | − |
| { | 0 | + |
| A | 1 | + |
| B | 2 | + |
| C | 3 | + |
| D | 4 | + |
| E | 5 | + |
| F | 6 | + |
| G | 7 | + |
| H | 8 | + |
| I | 9 | + |
"""
@doc """
Converts a string in signed overpunch format to an integer.
If successful, returns a tuple in the form of `{:ok, integer}`. Otherwise, it
returns `:error`.
## Examples
iex> SignedOverpunch.convert("100{")
{:ok, 1000}
iex> SignedOverpunch.convert("100}")
{:ok, -1000}
iex> SignedOverpunch.convert("00I")
{:ok, 9}
iex> SignedOverpunch.convert("000")
:error
iex> SignedOverpunch.convert("GOTCHA")
:error
"""
def convert(string) when is_bitstring(string) do
string
|> Integer.parse
|> get_profile
|> perform_conversion
|> apply_sign
|> format_return
end
@doc """
Converts a string in signed overpunch format to an integer.
Similar to `SignedOverpunch.convert/1`, but raises an `ArgumentError` if the
input provided is not valid signed overpunch.
## Examples
iex> SignedOverpunch.convert!("100{")
1000
iex> SignedOverpunch.convert!("100}")
-1000
iex> SignedOverpunch.convert!("00I")
9
iex> SignedOverpunch.convert!("000")
** (ArgumentError) invalid signed overpunch value: 000
iex> SignedOverpunch.convert!("GOTCHA")
** (ArgumentError) invalid signed overpunch value: GOTCHA
"""
def convert!(string) do
case convert(string) do
{:ok, int} -> int
:error -> raise ArgumentError, @error_message <> string
end
end
defp perform_conversion({int, {neg_or_pos, add}}) do
{neg_or_pos, int * 10 + add}
end
defp perform_conversion(_), do: :error
defp apply_sign({:pos, int}) when is_integer(int), do: int
defp apply_sign({:neg, int}) when is_integer(int), do: 0 - int
defp apply_sign(_), do: :error
defp get_profile({int, overpunch_char}) do
{int, profile(overpunch_char)}
end
defp get_profile(_), do: :error
defp format_return(int) when is_integer(int), do: {:ok, int}
defp format_return(:error), do: :error
defp profile("}"), do: {:neg, 0}
defp profile("J"), do: {:neg, 1}
defp profile("K"), do: {:neg, 2}
defp profile("L"), do: {:neg, 3}
defp profile("M"), do: {:neg, 4}
defp profile("N"), do: {:neg, 5}
defp profile("O"), do: {:neg, 6}
defp profile("P"), do: {:neg, 7}
defp profile("Q"), do: {:neg, 8}
defp profile("R"), do: {:neg, 9}
defp profile("{"), do: {:pos, 0}
defp profile("A"), do: {:pos, 1}
defp profile("B"), do: {:pos, 2}
defp profile("C"), do: {:pos, 3}
defp profile("D"), do: {:pos, 4}
defp profile("E"), do: {:pos, 5}
defp profile("F"), do: {:pos, 6}
defp profile("G"), do: {:pos, 7}
defp profile("H"), do: {:pos, 8}
defp profile("I"), do: {:pos, 9}
defp profile(_), do: :error
end