Here is another way to do the counting, resulting in smaller code:
Mix.install([{:unicode_set, "~> 1.0"}])
defmodule ProbablyFaster do
require Unicode.Set
case_ast =
for s <-
Unicode.Set.to_pattern!(
"[[:Lu:], [:Ll:], [:Lt:], [:Lm:], [:Lo:], [:Nl:], [:Mn:], [:Mc:], [:Nd:], [:Pc:], [:Cf:]]"
) do
<<c :: utf8>> = s
hd(
quote do
unquote(c) -> true
end
)
end ++
quote do
_ -> false
end
def case_fn(binary) do
size = count_bytes(binary)
<<pre::binary-size(^size), post::binary>> = binary
{pre, post}
end
defp count_bytes(binary) do
rest = do_count_bytes(binary)
byte_size(binary) - byte_size(rest)
end
defp do_count_bytes(binary) do
case binary do
<<c :: utf8, rest :: binary>> ->
accept? = case c do
unquote(case_ast)
end
case accept? do
true -> do_count_bytes(rest)
false -> binary
end
_ ->
binary
end
end
end
The resulting Erlang code will look this:
case_fn(_binary@1) ->
_size@1 = count_bytes(_binary@1),
<<_pre@1:_size@1/binary, _post@1/binary>> = _binary@1,
{_pre@1, _post@1}.
count_bytes(_binary@1) ->
_rest@1 = do_count_bytes(_binary@1),
erlang:byte_size(_binary@1) - erlang:byte_size(_rest@1).
do_count_bytes(_binary@1) ->
case _binary@1 of
<<_c@1/utf8, _rest@1/binary>> ->
_accept?@1 = case _c@1 of
44 -> true;
48 -> true;
49 -> true;
50 -> true;
.
.
.
917996 -> true;
917997 -> true;
917998 -> true;
917999 -> true;
_ -> false
end,
case _accept?@1 of
true -> do_count_bytes(_rest@1);
false -> _binary@1
end;
_ -> _binary@1
end.