[erlang-questions] Beginners question on pattern matching

Bob Ippolito <>
Fri Oct 5 18:23:55 CEST 2007


On 10/5/07, Alexander Lamb <> wrote:
> Hello List,
>
> I am starting on Erlang. I read most of the new Erlang book. However, I am
> lost with something really simple and probably stupid.
>
> I am reading a file, line by line.
>
> Each line is in the form
>
> "a_code" , a_date
>
> The quotes (") are present in the file, as well as the comma. For example:
>
> "C51CBA979E4311D67900201842D2EEE81",2003-08-07
>
>
> I would like to cut the string into pieces (to be able to modify it...).
> Again, this is a test to learn Erlang, I know how to do this in two lines of
> Ruby :-). I could also probably use a built in function to parse the string.
> But I would like to understand pattern matching and lists.
>
> So I wrote this, first read the file:
>
> start() ->
>
>  case file:open("ENRL_ENROLLMENT.csv",read) of
>
>  {ok, S} ->
>  Val = do_read(S),
>  file:close(S),
>  Result = process_lines(Val),
>  {ok,Result};
>
>  {error, Why} ->
>
>  {error, Why}
>
>  end.
>
> Then the lines:
>
> do_read(S) ->
>
>  case io:get_line(S,'') of
>
>  eof -> [];
>  Line -> [Line | do_read(S)]
>
>  end.

This isn't tail recursion, so your process will probably crash if you
read a very long file. You'll want to rewrite this to use an
accumulator and then lists:reverse. You could even process the lines
as you read them to save you from creating a second big list.

> Then process each line in the list of lines:
>
> process_lines(Lines) ->
>
>  [Date || [_Code | "," ++ Date] <- Lines].
>
>
> Something is wrong, because it compiles but here is what I get:
>
> 11> c(csv_convert.erl).
> {ok,csv_convert}
> 12> csv_convert:start().
> {ok,[]}
>
> If each line is actually a list of characters, why can't I match the pattern
> I want???

Because the pattern you want doesn't mean what you think it does, and
list comprehensions ignore bad matches:

1> [_Code | "," ++ Date] = "Code,Date".
** exited: {{badmatch,"Code,Date"},[{erl_eval,expr,3}]} **
2> [_Code | "," ++ Date] = "C,Date".
"C,Date"
3> {_Code, Date}.
{67,"Date"}

You can't actually write a pattern that matches the tail of a list
with a variable length head. If you knew exactly how long the code was
going to be you could write a very ugly pattern though.

1> Code ++ "," ++ Date = "Code,Date".
** 1: illegal pattern **
2> [_,_,_,_,$, | Date] = "Code,Date".
"Code,Date"
3> Date.
"Date"

You should probably write a function to do it though..

1> tl(lists:dropwhile(fun (C) -> C =/= $, end, "Code,Date")).
"Date"

-bob



More information about the erlang-questions mailing list