henrique-marcomini-m
How to pattern match (or guards) if a string is alphanumeric
I have the following code:
defp has_char_in_string?(value), do: Regex.match?(~r/[^\d]/, value)
def somefun(arg) do
case has_char_in_string?(arg) do
true -> foo()
false -> bar()
end
end
And I really want to keep this regex within this module and do not externalize this logic. But I also want to use pattern matching or guards instead of a case. Is this even possible? And if it is, how?
Thanks in advance
Most Liked
peerreynders
Probably not what you are looking for:
def somefun(true),
do: foo()
def somefun(false),
do: bar()
def somefun(arg) when is_binary(arg),
do: Regex.match?(~r/[^\d]/, arg)
|> somefun()
or
defp p_somefun(true),
do: foo()
defp p_somefun(false),
do: bar()
def somefun(arg) when is_binary(arg) do
Regex.match?(~r/[^\d]/, arg)
|> p_somefun()
end
al2o3cr
It’s possible, especially if the regular expression is simple - you can translate the regex into its corresponding finite state machine and represent that with pattern matching:
defmodule RegexRecursion do
def somefun(arg) do
call_bar(arg)
end
defp call_bar("0" <> rest), do: call_bar(rest)
defp call_bar("1" <> rest), do: call_bar(rest)
defp call_bar("2" <> rest), do: call_bar(rest)
defp call_bar("3" <> rest), do: call_bar(rest)
defp call_bar("4" <> rest), do: call_bar(rest)
defp call_bar("5" <> rest), do: call_bar(rest)
defp call_bar("6" <> rest), do: call_bar(rest)
defp call_bar("7" <> rest), do: call_bar(rest)
defp call_bar("8" <> rest), do: call_bar(rest)
defp call_bar("9" <> rest), do: call_bar(rest)
defp call_bar(""), do: bar()
defp call_bar(x) when is_binary(x), do: foo()
defp foo(), do: IO.puts("foo")
defp bar(), do: IO.puts("bar")
end
Here, the regex [^\d] translates to a state machine that stays in call_bar as long as each character is 0-9, actually calls bar given an empty string, and calls foo otherwise.
If the regex doesn’t involve backreferences or lookaheads (so it’s a theory-of-languages regular expression), it’s always possible to do this.
HOWEVER
The example above is a good example of how this approach obfuscates what should have been code like this:
defmodule RegexRecursionSimple do
def somefun(arg) when is_binary(arg) do
if Regex.match?(~r/[^\d]/, arg) do
foo()
else
bar()
end
end
defp foo(), do: IO.puts("foo")
defp bar(), do: IO.puts("bar")
end
I’m very curious what’s motivating the preference for pattern matching here; it’s not the right tool for the job.
hauleth
TBH I would say that Regex is overkill there. And your pattern match can be improved:
def somefun(<<num>> <> rest) when num in ?0..?9, do: call_bar(rest)
def somefun(""), do: bar()
def somefun(bin) when is_binary(bin), do: foo()
The problem with regular expressions the use backtracking engine (and PCRE is such engine) is that it can explode to O(n^2) with some expressions (namely nested wildcard matches). And such cases have been spotted on the wild with pretty simple expressions.







