2
votes

I wanted to read from a file and then store it in the form of list. Every time there is a comma,it will combine all the characters before the comma to form a new word. A new line will indicate it is a new sub-list. It is very similar to what java can do when they read a file. I am learning prolog and having issue with reading file and getting them as input to perform different operations. Do you know any methods that can help me read a file and use those data as input for different functions? Thank you.

Read File:

Thales,Olivia,Jackson,Sophia

Canada Post,Sophia,Jackson,Olivia

Cisco,Olivia,Sophia,Jackson

Code:

read_from_file(File, A):-
   open(File, read, Stream),
   get_char(Stream, Char1),
   process_the_stream(Char1, Stream, A),
   close(Stream).

write_on_file(File,Text):-
   open(File, append, Stream),
   write(Stream, Text), nl,
   close(Stream).

process_the_stream(end_of_file, _, []):- !.

process_the_stream(Char, Stream, [Char|B]):-
   write(Char),
   get_char(Stream, Char2),
   process_the_stream(Char2, Stream, B).

Current output:

A = ['T',h,a,l,e,s,',','O',l,i,v,i,a,',','J',a,c,k,s,o,n,',','S',o,p,h,i,a,'\n','C',a,n,a,d,a,' ','P',o,s,t,',','S',o,p,h,i,a,',','J',a,c,k,s,o,n,',','O',l,i,v,i,a,'\n','C',i,s,c,o,',','O',l,i,v,i,a,',','S',o,p,h,i,a,',','J',a,c,k,s,o,n]

Desire Output:

A = [[Thales, Olivia, Jackson, Sophia], [Canada Post, Sophia, Jackson, Olivia], [Cisco, Olivia, Sophia, Jackson]]

2
If you are using SWI-Prolog consider read_string/5Guy Coder
Is it something that i have to import like prolog library? I am having trouble with importing library and spent hours on how to import library but it is not working out for me.Ta Anh Minh
Are you using SWI-Prolog? That is the only one I use. If so, what version?Guy Coder
Oh i am using a different prolog version, just installed the swi and now i am able to use the library. Thank you.Ta Anh Minh
@GuyCoder I imported library(csv) and i read the file and get this output: ?- csv_read_file("coop_e_3x3.csv", Rows). Rows = [row('Thales', 'Olivia', 'Jackson', 'Sophia'), row('Canada Post', 'Sophia', 'Jackson', 'Olivia'), row('Cisco', 'Olivia', 'Sophia', 'Jackson')]. Do you know how to get access to the list? I tried to get head and it return me this: A = row('Thales', 'Olivia', 'Jackson', 'Sophia'). I tried to get head again and hoping that it would give me Thales but all it return was false. Same with tail, it return false when i get tail of A.Ta Anh Minh

2 Answers

1
votes

This uses SWI-Prolog 8.x.y

:- use_module(library(csv)).

process_csv(File,Values) :-
    csv_read_file(File,Rows),
    rows_to_values(Rows,Values).

rows_to_values([],[]).
rows_to_values([Row|Rows],[Values|Values0]) :-
    row_to_values(Row,Values),
    rows_to_values(Rows,Values0).

row_to_values(Row,Values) :-
    Row =.. List,
    List = [_Functor|Values].

Example run

?- process_csv('C:/Users/Groot/Documents/Projects/Prolog/SO_question_189_data.txt',Values).
Values = [['Thales', 'Olivia', 'Jackson', 'Sophia'], ['Canada Post', 'Sophia', 'Jackson', 'Olivia'], ['Cisco', 'Olivia', 'Sophia', 'Jackson']].

The reason this answer is different than your desired answer is that the atoms are bookended with ' so that they are atoms and not variables because variables start with upper case letters.

If you prefer something simpler then

:- use_module(library(csv)).

process_csv(File,Values) :-
    csv_read_file(File,Rows),
    maplist(row_to_values,Rows,Values).

row_to_values(Row,Values) :-
    Row =.. [_Functor|Values].
0
votes

A simple portable solution using Logtalk, which you can run in most Prolog systems:


:- object(process).

    :- public(data/2).
    data(File, Data) :-
        open(File, read, Stream),
        reader::line_to_codes(Stream, Line),
        process_data(Line, Stream, Data),
        close(Stream).

    process_data(end_of_file, _, []).
    process_data([Code| Codes], Stream, [Names| Data]) :-
        atom_codes(Atom, [Code| Codes]),
        atom::split(Atom, ',', Names),
        reader::line_to_codes(Stream, Line),
        process_data(Line, Stream, Data).

:- end_object.

Sample call, assuming a data file with no empty lines and no spaces between names as in the question sample data file contents:

| ?- {types(loader), reader(loader), process}.
...
yes

| ?- process::data('data.txt', Names).
Names = [['Thales', 'Olivia', 'Jackson', 'Sophia'], ['Canada Post', 'Sophia', 'Jackson', 'Olivia'], ['Cisco', 'Olivia', 'Sophia', 'Jackson']]
yes