Erlang/OTP Forums

Author Message

<  Erlang  ~  getlines from a file

selmi.dhia
Posted: Tue Jun 29, 2010 3:21 pm Reply with quote
Joined: 29 Jun 2010 Posts: 5
I am a beginner in erlang,I want to read lines from a file (.erl or .txt) and store those lines as elements into a list.I tried this code:
--------------------------------------------------
-module(read).
-export([readlines/1]).

readlines(FileName) ->
{ok, Device} = file:open(FileName, [read]),
get_all_lines(Device,[]).

get_all_lines(Device, Accum) ->
case io:get_line(Device, []) of
eof -> file:close(Device), Accum;
Line -> get_all_lines(Device, Accum ++ [Line])
end.
-----------------------
and for a file containing a number in each line, I got a result like this:
["12\n","5\n","35\n","4\n","11\n","123\n","867\n","10\n","201\n"]

How can I have a result without the "\n" character in the list's elements like this:
["12","5","35","4","11","123","867","10","201"]?

or further a list of numbers not of strings like this:
[12,5,35,4,11,123,867,10,201]?
View user's profile Send private message MSN Messenger
zajda
Posted: Wed Jun 30, 2010 9:01 am Reply with quote
User Joined: 22 Aug 2009 Posts: 83
please, analyse following changes (and later points to see why its wrong):

Code:
-module(read).
-export([readlines/1]).

readlines(FileName) ->
    {ok, Device} = file:open(FileName, [read]),
    lists:reverse(get_all_lines(Device,[])).

get_all_lines(Device, Accum) ->
    case io:get_line(Device, []) of
        eof -> file:close(Device), Accum;
        [Line|"\n"] ->
            get_all_lines(Device, [list_to_integer([Line])|Accum])
    end.


there are three tricks Wink and above code is not the best example of good erlang code. This is why:

1. I pattern match on line to extract a number, but if in line there would be something else like '1 2\n' it would fall.

2. When Line is bounded it is actually an integer (because this is how chars are represented in erlang). It is not visible in this example very well, and it has to be wrapped again in list to get changed into proper value of integer ("1" is 49 and then integer_to_list([49]) is 1)

3. It is better to add new stuff as a head of a list. Thats why I had to reverse the order when function returned.
Here, tail recursion is lost, but it could be solved by extra clause of get_all_lines/2 and do not

code returns sth like that:

read:readlines("somefile.txt").
[1,2,3,4,5,6]



MichaƂ Zajda
------------------
Erlang Solutions Ltd
View user's profile Send private message
selmi.dhia
Posted: Wed Jun 30, 2010 10:45 am Reply with quote
Joined: 29 Jun 2010 Posts: 5
thank you, I got all the tricks, but I tried to compile your code and its ok,after that I tried a call: read:readlines("file.erl"). where file.erl is a file conataining on number in each line with no spaces,I got an error as shown below:

8> H=read:readlines("c:/Users/student/Desktop/file.erl").
** exception error: no case clause matching "12\n"
in function read:get_all_lines/2
in call from read:readlines/1
why it doesn't work Question Confused
View user's profile Send private message MSN Messenger
zajda
Posted: Wed Jun 30, 2010 11:16 am Reply with quote
User Joined: 22 Aug 2009 Posts: 83
space doesn't matter, it is number of chars and it works only for one.

It is because, head of a list in pattern [Line|"\n"] is just one char (so Line is one char).

Take a look at string module documentation ( http://erlang.org/doc/man/string.html) and modify whole line in side of case clause, not in pattern. It is quit slow, so later for performance reason you can use regexps (http://erlang.org/doc/man/re.html)
View user's profile Send private message
selmi.dhia
Posted: Thu Jul 01, 2010 9:07 am Reply with quote
Joined: 29 Jun 2010 Posts: 5
ok it works perfectly with string:substr/3..I tried so far with a file that can have many numbers in the same line separated with a space:"12 999.." for that I used string:tokens/2 in this code:
------------
-module(read).
-export([readlines/1]).

readlines(FileName) ->
{ok, Device} = file:open(FileName, [read]),
lists:reverse(get_all_lines(Device,[])).

get_all_lines(Device, Accum) ->
case io:get_line(Device, []) of
eof -> file:close(Device), Accum;
Line ->get_all_lines(Device,[string:tokens((string:substr(Line,1,(string:len(Line))-1))," ")|Accum])
end.
----------
the problem is that I had a result: [["12","999"],["5"],["35"],["4"],["11"],["123"],["867"],["10"],
["201"]] instead of having this ["12","999","5","35"|..]
any solution? otherwise,how can I use the "re" module?
View user's profile Send private message MSN Messenger
zajda
Posted: Sat Jul 03, 2010 5:27 pm Reply with quote
User Joined: 22 Aug 2009 Posts: 83
you can flatten the list with lists:flatten/1 but in this case output would be too flat Wink

I think that the simplest way is to use ++ again.

Code:
-module(read).
-export([readlines/1]).

readlines(FileName) ->
    {ok, Device} = file:open(FileName, [read]),
    get_all_lines(Device, io:get_line(Device, []), []).

get_all_lines(Device, eof, Accum) ->
    file:close(Device),
    lists:reverse(Accum);
get_all_lines(Device, Line, Accum) ->
    Extract = fun(Input) ->
                      string:tokens((string:substr(Input,1,(string:len(Input))-1))," ")
              end,
    get_all_lines(Device, io:get_line(Device, []), Extract(Line) ++ Accum).


and here with re:
Code:
-module(read).
-export([readlines/1]).

readlines(FileName) ->
    {ok, Device} = file:open(FileName, [read]),
    get_all_lines(Device, io:get_line(Device, []), []).

get_all_lines(Device, eof, Accum) ->
    file:close(Device),
    lists:reverse(Accum);
get_all_lines(Device, Line, Accum) ->
    Extract = fun(Input) ->
                      re:split(Input,"[ \n]",[{return,list},trim])
              end,
    get_all_lines(Device, io:get_line(Device, []), Extract(Line) ++ Accum).


in case of more complicated regexp you can compile it with re:compile in the initializing function and pass it on.
View user's profile Send private message
selmi.dhia
Posted: Mon Jul 05, 2010 8:34 am Reply with quote
Joined: 29 Jun 2010 Posts: 5
thank you..I got the result that I need.. Laughing
View user's profile Send private message MSN Messenger
wuji
Posted: Tue Sep 04, 2012 7:43 am Reply with quote
User Joined: 10 Aug 2012 Posts: 654
all stay?'" Denniston said.The team agreed."I love swimming under Dave, Dave, replica designer *beep* Dave, and I think he is a good fit," said
Kamber, a member of the Paralympics swimming team. "He understands understands [h2]cheap jordans[/h2] understands each of our training needs."Recently, Denniston was announced as
head coach of the 2012 Paralympic Resident Swim team in in [h4]cheap polo shirts[/h4] in Colorado Springs -- the same position his mentor Flowers
before him.Denniston said that if he had to sum up up [h2]replica designer *beep*[/h2] up his experiences since his 2005 accident in a single
View user's profile Send private message
dongdongwu
Posted: Wed Sep 19, 2012 8:35 am Reply with quote
User Joined: 19 Sep 2012 Posts: 236
Girls would refuse to even leave their replicas behind. specifically when the product beats the complete meaning of the Christian Louboutin men outlet; in conditions of good quality and detailing.If Cinderella was residing in your twenty primary century as opposed to the aged a single then there would not be any 'Happy actually after'. properly appears like girls nowadays are as well fond of the strong;Christian Louboutin Men Shoes to leave them in your center of nowhere.Christian Louboutin for men Shoes would arrive true handy being a excellent handbag using the glimpse and really feel belonging to the authentic but at a very much lesser price tag adding as very much as types picture in your process.
View user's profile Send private message

Display posts from previous:  

All times are GMT
Page 1 of 1
This forum is locked: you cannot post, reply to, or edit topics.

Jump to:  

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum