Reputation: 3516
I know how to do this with regular String operations, but I'm curious if it's possible to match in one step.
Let's say I have accounts/123123/order/234234234
. It's from an external source, so while I know that accounts/
and /order
are always fixed length/value, the numbers might not always be a fixed length. Is there any way to do binary pattern matching here? Or anything better than a few String operations?
Upvotes: 3
Views: 537
Reputation: 14042
If you are looking for something easy to read, you may convert the binary to list and use the io_lib:format/2 function:
1> Tag = <<"accounts/123123/order/234234234">>.
<<"accounts/123123/order/234234234">>
2> {ok,[ACC,ORD],_} = io_lib:fread("accounts/~d/order/~d",binary_to_list(Tag)).
{ok,[123123,234234234],[]}
3>
Upvotes: 0
Reputation: 48599
Other options...
In erlang:
~$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> binary:split(<<"accounts/123123/order/234234234">>, <<"/">>, [global]).
[<<"accounts">>,<<"123123">>,<<"order">>,<<"234234234">>]
In elixir:
~$ iex
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.8.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> :binary.split("accounts/123123/order/234234234", "/", [:global])
["accounts", "123123", "order", "234234234"]
With elixir regexes:
iex(3)> Regex.scan( ~r{[^/]+}, "accounts/123123/order/234234234") |> List.flatten()
["accounts", "123123", "order", "234234234"]
Upvotes: 0
Reputation: 121000
There is nothing you cannot do with a bit of metaprogramming :)
defmodule AccOrd do
@input "accounts/123123/order/234234234"
for acc <- 1..42 do
def match(<<"accounts/", acc :: binary-size(unquote(acc)),
"/order/", ord :: binary>>), do: {acc, ord}
end
def test, do: match(@input)
end
AccOrd.test()
#⇒ {"123123", "234234234"}
Here we have basically built 42
clauses of match/1
function. One of them would match your input and voilà.
Upvotes: 1
Reputation: 5973
if it's possible to match in one step
We can only pattern match when we know the sizes of all the left pieces. As far as I'm aware, this can't be done as one pattern match.
anything better than a few String operations?
What about just one String operation?
iex> tag = "accounts/123123/order/234234234"
iex> ["accounts", account, "order", order] = String.split(tag, "/")
iex> account
"123123"
iex> order
"234234234"
Regex is also a good option
iex> tag = "accounts/123123/order/234234234"
iex> regex = ~R{^accounts/(?<account>\d+)/order/(?<order>\d+)$}
iex> Regex.named_captures(regex, tag)
%{"account" => "123123", "order" => "234234234"}
Upvotes: 7