Current section
Files
Jump to
Current section
Files
lib/postal_code.ex
defmodule PostalCode do
@moduledoc """
Postal code parser for the Norwegian postal code system.
"""
alias CSV
@posten_file 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)
@erik_file Path.join(File.cwd!(), "postnummer.csv")
|> File.stream!()
|> CSV.decode()
|> Enum.map(fn x ->
case x do
{:ok, list} ->
Enum.at(
Enum.map(list, fn y ->
y |> String.replace("\r", "") |> String.split("\t")
end),
0
)
end
end)
@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, :invalid_length}
def postal_code_to_place(_postal_code),
do: {:error, :invalid_type}
def postal_code_to_county(postal_code)
when is_binary(postal_code) and bit_size(postal_code) == 32 do
case get_matching_postal_code(postal_code, :erik) do
[_, _, _, _, _, _, _, _, county, latitude, longitude, _, _, _] ->
{:ok, %{
"county" => county,
"location" => %{
"latitude" => latitude,
"longitude" => longitude
}
}}
nil ->
:no_results
end
end
def postal_code_to_county(postal_code) when is_binary(postal_code),
do: {:error, :invalid_length}
def postal_code_to_county(_), do: {:error, :invalid_type}
def postal_code_to_location(postal_code)
when is_binary(postal_code) and bit_size(postal_code) == 32 do
case get_matching_postal_code(postal_code, :erik) do
[_, _, _, _, _, _, _, _, _, latitude, longitude, _, _, _] ->
{latitude, longitude}
_ ->
:no_results
end
end
def postal_code_to_location(postal_code) when is_binary(postal_code),
do: {:error, "Length must be 4."}
def postal_code_to_location(_postal_code),
do: {:error, "Invalid type of postal code, must be string"}
defp get_matching_postal_code(postal_code) do
Enum.find(@posten_file, fn x -> Enum.at(x, 0) == postal_code end)
end
defp get_matching_postal_code(postal_code, :erik) do
Enum.find(@erik_file, fn x -> Enum.at(x, 0) == postal_code end)
end
end