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
No, there is no way to make this regex or even something semantically equivalent into a guardsave predicate.
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.
Last Post!
kip
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
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #elixirconf-us
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex









