snewcomer
snewcomer

Reputation: 2135

Pattern match on substring in Elixir

How can I pattern match on a string where passing either side of the semicolon will return true? In other words, is there a simple way to pattern match it contains the substring?

@matched_string "x-wat"

def match(@matched_string), do: true

match("x-wat") # true
match("x-wat; s-wat") # true
match("s-wat; x-wat") # true
match("s-wat") # false
match("x-wat-y") #false

Upvotes: 7

Views: 6455

Answers (2)

ryanwinchester
ryanwinchester

Reputation: 12157

You can't for the reasons @Dogbert explained, but there are lots of ways to check for substrings.

If you didn't have constraints, you could just do

iex> "s-wat; x-wat" =~ "x-wat"
true

iex> String.contains? "s-wat; x-wat", "x-wat"
true

But you have some constraints so you can get creative. I'll add another example on top of existing answers:

One example using Regex:

@matched_string "x-wat"

def match?(string) do
  ~r/^(.+; )?(#{@matched_string})(; [^\s]+)?$/ |> Regex.match?(string)
end

Verify:

iex(1)> import Regex
Regex

iex(2)> matched_string = "x-wat"
"x-wat"

iex(3)> r = ~r/^(.+; )?(#{matched_string})(; [^\s]+)?$/
~r/^(.+; )?(x-wat)(; [^\s]+)?$/

iex(4)> match?(r, "x-wat")
true

iex(5)> match?(r, "x-wat; s-wat")
true

iex(6)> match?(r, "s-wat; x-wat")
true

iex(7)> match?(r, "s-wat")
false

iex(8)> match?(r, "x-wat-y")
false

Upvotes: 2

Dogbert
Dogbert

Reputation: 222448

No, this cannot be done with pattern matching. You can match the prefix of a string or if you know the length of each part in the beginning of the string, you can specify the size of those and match that e.g. <<_::size(4), @matched_string, _::binary>>, but you can't in general match any arbitrary substring. In this case, you can instead split on ;, trim the strings, and check if it contains "x-wat":

def match(string) do
  string |> String.split(";") |> Enum.map(&String.trim/1) |> Enum.member?(string)
end

Upvotes: 14

Related Questions