Hello!
Playing with Elixir, I’m wondering if I could make the following “look ahead” pattern matching a bit “better”, that is, a bit less verbose.
I’m not interested in using a regex btw.
# echo ./pattern.ex | entr -c elixir /_
ExUnit.start()
defmodule Pattern do
def filter_map(str) do
filter_map(str, [])
end
defp filter_map(<<>>, acc), do: Enum.reverse(acc)
defp filter_map(<<n, rest::binary>>, acc) when n in ?0..?9 do
filter_map(rest, [n - ?0 | acc])
end
defp filter_map(<<?o, ?n, ?e, rest::binary>>, acc) do
filter_map(<<?n, ?e, rest::binary>>, [1 | acc])
end
defp filter_map(<<?t, ?w, ?o, rest::binary>>, acc) do
filter_map(<<?w, ?o, rest::binary>>, [2 | acc])
end
defp filter_map(<<?t, ?h, ?r, ?e, ?e, rest::binary>>, acc) do
filter_map(<<?h, ?r, ?e, ?e, rest::binary>>, [3 | acc])
end
defp filter_map(<<?f, ?o, ?u, ?r, rest::binary>>, acc) do
filter_map(<<?o, ?u, ?r, rest::binary>>, [4 | acc])
end
defp filter_map(<<?f, ?i, ?v, ?e, rest::binary>>, acc) do
filter_map(<<?i, ?v, ?e, rest::binary>>, [5 | acc])
end
defp filter_map(<<?s, ?i, ?x, rest::binary>>, acc) do
filter_map(<<?i, ?x, rest::binary>>, [6 | acc])
end
defp filter_map(<<?s, ?e, ?v, ?e, ?n, rest::binary>>, acc) do
filter_map(<<?e, ?v, ?e, ?n, rest::binary>>, [7 | acc])
end
defp filter_map(<<?e, ?i, ?g, ?h, ?t, rest::binary>>, acc) do
filter_map(<<?i, ?g, ?h, ?t, rest::binary>>, [8 | acc])
end
defp filter_map(<<?n, ?i, ?n, ?e, rest::binary>>, acc) do
filter_map(<<?i, ?n, ?e, rest::binary>>, [9 | acc])
end
defp filter_map(<<_, rest::binary>>, acc) do
filter_map(rest, acc)
end
end
defmodule PatternTest do
use ExUnit.Case
test "extract digits" do
assert Pattern.filter_map("1.abc.oneight--nineightseveninessixfivefourthreetwone0123456789") ==
[
1,
1,
8,
9,
8,
7,
9,
6,
5,
4,
3,
2,
1,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9
]
end
end