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

First Post!

NobbZ

NobbZ

No, there is no way to make this regex or even something semantically equivalent into a guardsave predicate.

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.

Last Post!

kip

kip

ex_cldr Core Team

Not forgotten! Both forms have canonical equivalence but they’re not identical as you say. Hence why its quite important to normalise to :nfc before checking casing for consistent results (unless implementing a full casing algorithm that is normal form independent). By the way, not only an issue for diacritics. Also for hangul. And not all decompositions are canonically equalivent.

For example half-width and full-width katakana characters will have the same compatibility decomposition and are thus compatibility equivalents; however, they are not canonical equivalents. They also aren’t cased so at least that’s not an issue here

Where Next?

Trending in Questions Top

lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" =&gt; #BSON.ObjectId&lt;58eb1a7a9ad169198c3dXXXX&gt;, "email" =&gt; ...
New
tj0
I’ve been following the steps here for the upgrade from 1.6 to 1.7 and it has gone relatively smoothly all the way till the phoenix_view ...
New
cgraham
Hi! What is currently the best library/method for parsing text and tabular data out of PDF files in Elixir or Erlang?
New
stefanchrobot
Hi, I need a way to handle data migrations in my application. I found an article by @wojtekmach about manual migrations: Automatic and ma...
New
stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
kip
Localize is the next generation localisation library for Elixir. Think of it as ex_cldr version 3.0. The first version will be released ...
New
webofbits
Squid Mesh is an open source workflow automation runtime for Elixir applications. It is aimed at Phoenix and OTP apps that want to defin...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
kip
In 2021 I started a new library called Tempo with the objective of modelling time as a set of intervals - not as instants. In 2022 I gave...
New

We're in Beta

About us Mission Statement