Created
May 3, 2019 07:06
-
-
Save Liru/c06b44a9d30fa378fec9a6427d9bbfa2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule GreekTax.Helper do | |
@moduledoc false | |
import NimbleParsec | |
@number [?0..?9] | |
def sep_number(sep) do | |
ascii_string(@number, 3) | |
|> ignore(string(sep)) | |
|> ascii_string(@number, 5) | |
|> ignore(string(sep)) | |
|> integer(1) | |
|> label("Greek tax number with \"#{sep}\" separator") | |
end | |
end | |
defmodule GreekTax do | |
@moduledoc """ | |
Documentation for GreekTax. | |
## Examples | |
iex> GreekTax.valid?("000000000") | |
false | |
iex> GreekTax.valid?("000000001") | |
false | |
iex> GreekTax.valid?("094277965") | |
true | |
iex> GreekTax.valid?("094 27796 5") | |
true | |
iex> GreekTax.valid?("094-27796-5") | |
true | |
iex> GreekTax.valid?("09427796") | |
false | |
iex> GreekTax.valid?("094 27796 a") | |
false | |
""" | |
import NimbleParsec | |
import GreekTax.Helper | |
defcombinatorp( | |
:tax_number, | |
choice([sep_number(""), sep_number(" "), sep_number("-")]) | |
) | |
defparsec(:parse, parsec(:tax_number)) | |
def valid?(tax_number) do | |
case parse(tax_number) do | |
{:error, _, _, _, _, _} -> | |
false | |
{:ok, ["000", "00000", 0], _, _, _, _} -> | |
false | |
{:ok, [num1, num2, check_digit], _, _, _, _} -> | |
Enum.flat_map([num1, num2], &String.graphemes/1) | |
|> Enum.map(&String.to_integer/1) | |
|> valid_checksum?(check_digit) | |
end | |
end | |
@multipliers 8..1 |> Enum.map(&(:math.pow(2, &1) |> trunc)) | |
defp valid_checksum?(numbers, check_digit) do | |
check_digit == | |
Enum.zip(numbers, @multipliers) | |
|> Enum.map(&mult/1) | |
|> Enum.sum() | |
|> rem(11) | |
|> case do | |
10 -> 0 | |
x -> x | |
end | |
end | |
defp mult({x, y}), do: x * y | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks @Liru! I've adopted some of your recommendations, i.e breaking the code to more functions, the usage of multipliers and zip to make the algorith logic easier and piping the final case (I didn't really know that case could be piped): https://github.com/spapas/validate_greek_tax_number/blob/master/lib/validate_gr_tax_num.ex
For the NimbleParsec I'll prefer my own (simpler) logic because I don't really want any dependencies and I think that using the parsing lib makes the code more difficult to understand. Also notice that the space or dash does not need to be in a specific position i.e the string 0 9 4 27 796 5 would also be valid (i.e I don't care where that whitespace is).
Thanks again!