You can use Regex.scan
instead of Regex.replace
. Probably not so fast, but it works
Regex.scan(~r/(.*?>)([^&<]+)(<\/span>)/s, html, capture: :all_but_first)
|> Enum.map_reduce(0, fn [l, c, r], acc ->
c =
c
|> String.split()
|> Enum.with_index()
|> Enum.map(fn {char, index} -> "<span id='CHAR-#{index + acc}'>#{char}</span>" end)
{[l, c, r], acc + length(c)}
end)
|> elem(0)
|> IO.puts()