[erlang-questions] What is allowed in a pattern in terms of string concatenation?

23 views
Skip to first unread message

Daniel Dormont

unread,
Jun 27, 2011, 11:52:44 AM6/27/11
to erlang-questions Questions
Suppose I want to test that a certain string String1 ends with a certain other string String2. The best I could come up with is:

case string:substr(lists:reverse(String1), 1, length(String2)) of
String2 -> ok;
_ -> not_ok
end

I was thinking there must be a better way, but various attempts along the lines of
case String1 of
_ ++ String2 -> ok;

all returned "illegal pattern" errors. I couldn't find a clear explanation online of when exactly ++ is allowed in a pattern and when it's not, so I'm a bit stumped. Is there a better way?

thanks,
Dan

PS I'm aware of regexp and re, but my current environment is a hybrid of R12 and R13B so I'm a bit hesitant to involve either one right now.
_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://erlang.org/mailman/listinfo/erlang-questions

kevin montuori

unread,
Jun 27, 2011, 12:00:59 PM6/27/11
to Daniel Dormont, erlang-questions Questions
On Mon, Jun 27, 2011 at 11:52 AM, Daniel Dormont
<d...@greywallsoftware.com> wrote:
> Suppose I want to test that a certain string String1 ends with a certain other string String2.

Although it doesn't actually answer the question you asked, you might
try something like lists:suffix(String2, String1).

Cheers.
k.

--
kevin montuori

Reynaldo Baquerizo

unread,
Jun 27, 2011, 12:12:39 PM6/27/11
to Daniel Dormont, erlang-questions Questions
On Mon, 27 Jun 2011 11:52:44 -0400
Daniel Dormont <d...@greywallsoftware.com> wrote:

> Suppose I want to test that a certain string String1 ends with a
> certain other string String2. The best I could come up with is:
>
> case string:substr(lists:reverse(String1), 1, length(String2)) of
> String2 -> ok;
> _ -> not_ok
> end
>
> I was thinking there must be a better way, but various attempts along
> the lines of case String1 of
> _ ++ String2 -> ok;
>
> all returned "illegal pattern" errors. I couldn't find a clear
> explanation online of when exactly ++ is allowed in a pattern and
> when it's not, so I'm a bit stumped. Is there a better way?

I can think of one using pattern matching,

is_substring(Substr, Substr) ->
true;
is_substring(String, Substr) ->
[_|T] = String,
p5(T, Substr).

you'd have to wrap it in a try ... catch for badmatch

--
Reynaldo

Reynaldo Baquerizo

unread,
Jun 27, 2011, 12:16:57 PM6/27/11
to Daniel Dormont, erlang-questions Questions
On Mon, 27 Jun 2011 11:12:39 -0500
Reynaldo Baquerizo <reyna...@gmail.com> wrote:

> On Mon, 27 Jun 2011 11:52:44 -0400
> Daniel Dormont <d...@greywallsoftware.com> wrote:
>
> > Suppose I want to test that a certain string String1 ends with a
> > certain other string String2. The best I could come up with is:
> >
> > case string:substr(lists:reverse(String1), 1, length(String2)) of
> > String2 -> ok;
> > _ -> not_ok
> > end
> >
> > I was thinking there must be a better way, but various attempts
> > along the lines of case String1 of
> > _ ++ String2 -> ok;
> >
> > all returned "illegal pattern" errors. I couldn't find a clear
> > explanation online of when exactly ++ is allowed in a pattern and
> > when it's not, so I'm a bit stumped. Is there a better way?
>
> I can think of one using pattern matching,
>
> is_substring(Substr, Substr) ->
> true;
> is_substring(String, Substr) ->
> [_|T] = String,
> p5(T, Substr).

Oops, that should be:

is_substring(String, Substr) ->
[_|T] = String,

is_substring(T, Substr).

Jachym Holecek

unread,
Jun 27, 2011, 1:23:36 PM6/27/11
to Daniel Dormont, erlang-questions Questions
# Daniel Dormont 2011-06-27:

> Suppose I want to test that a certain string String1 ends with a certain
> other string String2. The best I could come up with is:

There are no strings in Erlang! :-)

> case string:substr(lists:reverse(String1), 1, length(String2)) of
> String2 -> ok;
> _ -> not_ok
> end

Kevin already pointed you to lists:suffix/2 which is good if suffix
isn't statically known, and very easy on the eyes too. If suffix is
known you could do:

has_suffix(L) ->
has_suffix2(lists:reverse(L)).

has_suffix2("xiffus" ++ _) ->
true;
has_suffix2(_) ->
false.

Which I think answers your other question. More precisely, AFAIU this

has_suffix2("xiffus" ++ _)

is just syntactic sugar for

has_suffix2([$x, $i, $f, $f, $u, $s | _])

So in a way you could perhaps say "++" isn't really supported in pattern
matching (but other will know this with more certainty). One doesn't see
"++" used very often overall, in my experience.

Also, this would have been so much cheaper (but harder to read) if you
used binaries to represent strings:

has_suffix(S, B) ->
has_suffix2(byte_size(B) - byte_size(S), S, B).

has_suffix2(N, _, _) when N < 0 ->
false;
has_suffix2(N, S, <<_:N/binary, D/binary>>) ->
S == D.

Or somesuch, you get the idea.

HTH,
-- Jachym

Daniel Dormont

unread,
Jun 27, 2011, 2:27:59 PM6/27/11
to Jachym Holecek, erlang-questions Questions

On Jun 27, 2011, at 1:23 PM, Jachym Holecek wrote:

> # Daniel Dormont 2011-06-27:
>> Suppose I want to test that a certain string String1 ends with a certain
>> other string String2. The best I could come up with is:
>
> There are no strings in Erlang! :-)
>

Right, fair enough.

>> case string:substr(lists:reverse(String1), 1, length(String2)) of
>> String2 -> ok;
>> _ -> not_ok
>> end
>
> Kevin already pointed you to lists:suffix/2 which is good if suffix
> isn't statically known, and very easy on the eyes too. If suffix is
> known you could do:
>
> has_suffix(L) ->
> has_suffix2(lists:reverse(L)).
>
> has_suffix2("xiffus" ++ _) ->
> true;
> has_suffix2(_) ->
> false.
>

I was not familiar with lists:suffix. I am now :) and it works fine for my purposes.

> Which I think answers your other question. More precisely, AFAIU this
>
> has_suffix2("xiffus" ++ _)
>
> is just syntactic sugar for
>
> has_suffix2([$x, $i, $f, $f, $u, $s | _])
>
> So in a way you could perhaps say "++" isn't really supported in pattern
> matching (but other will know this with more certainty). One doesn't see
> "++" used very often overall, in my experience.
>

Ok.

> Also, this would have been so much cheaper (but harder to read) if you
> used binaries to represent strings:
>
> has_suffix(S, B) ->
> has_suffix2(byte_size(B) - byte_size(S), S, B).
>
> has_suffix2(N, _, _) when N < 0 ->
> false;
> has_suffix2(N, S, <<_:N/binary, D/binary>>) ->
> S == D.
>

Right, unfortunately in the place where my module will be called, the string values are in lists, not binaries.

> Or somesuch, you get the idea.
>

Dan

Richard O'Keefe

unread,
Jun 27, 2011, 9:34:47 PM6/27/11
to Daniel Dormont, erlang-questions Questions

On 28/06/2011, at 3:52 AM, Daniel Dormont wrote:

> Suppose I want to test that a certain string String1 ends with a certain other string String2. The best I could come up with is:
>
> case string:substr(lists:reverse(String1), 1, length(String2)) of
> String2 -> ok;
> _ -> not_ok
> end
>
> I was thinking there must be a better way, but various attempts along the lines of
> case String1 of
> _ ++ String2 -> ok;
>
> all returned "illegal pattern" errors. I couldn't find a clear explanation online of when exactly ++ is allowed in a pattern and when it's not, so I'm a bit stumped.

Section 7.4 of the reference manual is the place where it says ++ is allowed
as a pattern, and the only thing it allows on the left of ++ is an explicit
string literal. A pattern like
"foo"++X
is just shorthand for
[$f,$o,$o|X]

If you want to check whether String1 ends with String2,
(a) you're going to need an even number of calls to lists:reverse/1
(b) you are going to be kicking yourself that you didn't read the
documentation for the 'lists' module
http://www.erlang.org/doc/man/lists.html
because
lists:suffix(String2, String1)
does exactly what you want (modulo returning 'true' or 'false').

Daniel Dormont

unread,
Jun 27, 2011, 11:58:03 PM6/27/11
to erlang-questions
On Mon, Jun 27, 2011 at 9:34 PM, Richard O'Keefe <o...@cs.otago.ac.nz> wrote:

On 28/06/2011, at 3:52 AM, Daniel Dormont wrote:

> Suppose I want to test that a certain string String1 ends with a certain other string String2. The best I could come up with is:
>
> case string:substr(lists:reverse(String1), 1, length(String2)) of
>       String2 -> ok;
>       _ -> not_ok
> end
>
> I was thinking there must be a better way, but various attempts along the lines of
>       case String1 of
>               _ ++ String2 -> ok;
>
> all returned "illegal pattern" errors. I couldn't find a clear explanation online of when exactly ++ is allowed in a pattern and when it's not, so I'm a bit stumped.

Section 7.4 of the reference manual is the place where it says ++ is allowed
as a pattern, and the only thing it allows on the left of ++ is an explicit
string literal.  A pattern like
       "foo"++X
is just shorthand for
       [$f,$o,$o|X]


I see. I'd found that section in my searching earlier, but hadn't made the connection that it has to be literal (in my defense, the manual doesn't exactly say that).
 
If you want to check whether String1 ends with String2,
(a) you're going to need an even number of calls to lists:reverse/1
(b) you are going to be kicking yourself that you didn't read the
   documentation for the 'lists' module
       http://www.erlang.org/doc/man/lists.html
   because
       lists:suffix(String2, String1)
   does exactly what you want (modulo returning 'true' or 'false').

Sometimes the challenge is not knowing where to look. I've used lists of course, but Erlang's lists is a pretty big module; it's easy to miss a few things here and there :)

Anyway, thanks.

dan

Reply all
Reply to author
Forward
0 new messages