Current section

Files

Jump to
mt940 lib parser.ex
Raw

lib/parser.ex

defmodule MT940.Parser do
use Timex
def parse(raw) when is_binary(raw) do
raw
|> String.strip
|> String.split(~r/\R-\R/, trim: true)
|> Stream.map(&parse_message/1)
|> Enum.to_list
end
defp parse_message(raw) when is_binary(raw) do
raw
|> String.strip
|> String.split(Regex.compile!("(\R?):\\d{1,2}\\w?:()"), on: :all_but_first, trim: true)
|> Stream.map(&String.strip/1)
|> Stream.chunk(2)
|> Stream.map(fn [k, v] -> {k |> remove_newline |> String.to_atom, split(k, v)} end)
|> Enum.into(Keyword.new)
end
defp split(":25:", v) do
case v |> String.contains?("/") do
true -> ~r/^(\d{8}|\w{8,11})\/(\d{1,23})(\D{3})?$/
false -> ~r/^(.+)(\D{3})?$/
end
|> Regex.run(v, capture: :all_but_first)
|> List.to_tuple
end
defp split(":28:", v) do
v |> statement_number
end
defp split(":28C:", v) do
v |> statement_number
end
defp split(":60" <> <<_>> <> ":", v) do
v |> balance
end
defp split(":61:", v) do
l = ~r/^(\d{6})(\d{4})?(C|RC|D|RD)(\D)?([0-9,]{2,15})(\w{4})(NONREF|.{1,22})(\/\/)?(\w{0,16})?([\s\R]{1,2})?(.{0,34})?$/
|> Regex.run(v, capture: :all_but_first)
|> List.update_at(4, &convert_to_decimal(&1))
|> List.update_at(0, &DateFormat.parse!(&1, "{YY}{M}{D}"))
value_date = l |> Enum.at(0)
booking_date = l |> Enum.at(1)
case booking_date do
"" -> l
_ -> l |> List.update_at(1, &DateFormat.parse!("#{value_date.year}#{&1}", "{YYYY}{M}{D}"))
end
|> List.to_tuple
end
defp split(":86:", v) do
s = ~r/^(\d{3})(\D)/
|> Regex.run(v, capture: :all_but_first)
case s do
[code, separator] ->
fields = v |> remove_newline |> String.split(Regex.compile!("(^\\d{3})?(\\#{separator})\\d{2}()"), on: :all_but_first, trim: true)
|> Stream.chunk(2)
|> Stream.map(fn [k, v] -> {String.to_integer(k), v |> String.replace(~r/\s{2,}/, " ") |> String.strip} end)
|> Enum.into(HashDict.new)
{code, fields}
_ ->
Regex.split(~r/\R/, v)
|> Enum.join(" ")
|> String.replace(~r/\s{2,}/, " ")
end
end
defp split(":62" <> <<_>> <> ":", v) do
v |> balance
end
defp split(":90" <> <<_>> <> ":", v) do
~r/^(\d{1,5})(\w{3})([0-9,]{1,15})$/
|> Regex.run(v, capture: :all_but_first)
|> List.to_tuple
end
defp split(_, v) when is_binary(v) do
v
end
defp balance(v) do
~r/^(\w{1})(\d{6})(\w{3})([0-9,]{1,15}).*$/
|> Regex.run(v |> remove_newline, capture: :all_but_first)
|> List.update_at(1, &DateFormat.parse!(&1, "{YY}{M}{D}"))
|> List.update_at(3, &convert_to_decimal(&1))
|> List.to_tuple
end
defp statement_number(v) do
~r/^(\d+)\/?(\d+)?$/
|> Regex.run(v |> remove_newline, capture: :all_but_first)
|> Enum.map(&String.to_integer/1)
|> List.to_tuple
end
defp convert_to_decimal(amount) when is_binary(amount) do
amount |> String.replace(",", ".") |> Decimal.new
end
defp remove_newline(string) when is_binary(string) do
~r(\R) |> Regex.replace(string, "")
end
end