Thank you all for your answers. @idi527, your solution looks very good to me, I finally did something inspired on that, but simpler for my usecase.
I needed to replace a tag in the text, so i had to find the tag name, and replace it with the new value. Kind of a template engine where I can substitute “Hello {{ first_name }}”
The engine get’s first all the tag names, store the name and the indexes, and later it get’s replaced by a value.
This is the code I used:
@regex ~r/{{\s*([a-zA-Z0-9_ ]*?)\s*}}/iu
def replace_tags(text, data) when is_binary(text) and is_map(data) do
result = Regex.run(@regex, text, return: :index)
case result do
nil ->
text
[{tag_start, tag_len}, {start, len}] ->
tag_name = slice_and_clean_tags(text, start, len)
value = Map.get(data, tag_name, "")
replace_binary(text, tag_start, tag_len, value)
|> replace_tags(data)
end
end
def replace_tags(text, _) when is_binary(text), do: text
def replace_tags(_, _), do: ""
defp slice_and_clean_tags(text, start, len) do
<<_before::binary-size(start), tag::binary-size(len), _after::binary>> = text
slugify(tag)
end
defp replace_binary(text, start, len, value)
when is_binary(text) and is_integer(start) and is_integer(len) do
until = start + len
<<first::binary-size(start), _::binary>> = text
<<_::binary-size(until), rest::binary>> = text
first <> value <> rest
end
defp replace_binary(text, _, _, _), do: text
The important line here is:
<<_before::binary-size(start), tag::binary-size(len), _after::binary>> = text
Thanks a lot for your help!