henrique-marcomini-m

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

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

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

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.

Where Next?

Popular in Questions Top

marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "eq...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New

Other popular topics Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41454 115
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30840 112
New
albydarned
Hello all! I am typing this post from my new MacBook Pro with the M1 chip. I’m loving it so far, and will probably use it as my daily dr...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New

We're in Beta

About us Mission Statement