The problem as it’s stated is kinda ambiguous, because it’s unclear whether @contact.name
whould be threated as a whole variable, or as @contact
variable followed by a regulat dot. In any case, this ambuiguity might be easily resolved using the code below as a scaffold. For instance, you might have a dedicated clause for "."
, check binding
there, and decide whether to move forward, or use the binding.
Erlang, and hence Elixir are extremely powerful in parsing text, thanks to pattern matching.
defmodule NaiveParser do
@varname ["." | Enum.map(?a..?z, &<<&1>>)]
def parse(input, binding),
do: do_parse(input, binding, {nil, ""})
defp do_parse("", binding, {var, result}), do: result <> bound(var, binding)
defp do_parse("@" <> rest, binding, {nil, result}),
do: do_parse(rest, binding, {"", result})
defp do_parse(<<c::binary-size(1), rest::binary>>, binding, {nil, result}),
do: do_parse(rest, binding, {nil, result <> c})
defp do_parse(<<c::binary-size(1), rest::binary>>, binding, {var, result})
when c in @varname,
do: do_parse(rest, binding, {var <> c, result})
defp do_parse(<<c::binary-size(1), rest::binary>>, binding, {var, result}),
do: do_parse(rest, binding, {nil, result <> bound(var, binding) <> c})
defp bound(nil, binding), do: ""
defp bound(var, binding) do
with {substitution, ^binding} <- Code.eval_string(var, binding),
do: to_string(substitution)
end
end
str = "Hello @contact.name, how are you. It looks like your age is @contact.age, so the solution of your problem is @solution"
NaiveParser.parse(str, [contact: %{age: 27, name: "Rahul"}, solution: "None"])
#⇒ "Hello Rahul, how are you. It looks like your age is 27, so the solution of your problem is None"