defmodule PostalCode do @moduledoc """ Postal code parser for the Norwegian postal code system. """ @doc """ Accepts a postal code in string format, and returns the postal place. ## Examples iex> PostalCode.postal_code_to_place("0186") {:ok, "OSLO"} iex> PostalCode.postal_code_to_place("0638") :no_results iex> PostalCode.postal_code_to_place(0186) {:error, "Invalid type of postal code, must be string."} iex> PostalCode.postal_code_to_place("018") {:error, "Length must be 4."} """ def postal_code_to_place(postal_code) when is_binary(postal_code) and bit_size(postal_code) == 32 do case get_matching_postal_code(postal_code) do [_postal_code, place, _county_code, _county_name, _category] -> {:ok, place} nil -> :no_results end end def postal_code_to_place(postal_code) when is_binary(postal_code), do: {:error, "Length must be 4."} def postal_code_to_place(_postal_code), do: {:error, "Invalid type of postal code, must be string."} @doc false defp get_postal_codes do Path.join(File.cwd!(), "postal_codes.csv") |> Path.expand(__DIR__) |> File.read!() |> String.split("\n") |> Enum.map(fn x -> x |> String.replace("\r", "") |> String.split("\t") end) end @doc false defp get_matching_postal_code(postal_code) do Enum.find(get_postal_codes(), fn x -> Enum.at(x, 0) == postal_code end) end end