How to ignore the first and last element on each line when reading from a text file in Prolog?Why do some DCG test cases use assertion( Rest == [])?Reading a line from a file in GNU PrologProlog importing facts from a formatted text fileHow to read from file using see and putting the content into a list in Prolog?Prolog I/O reading file and extracting info to usereading files in PrologGetting max element from a list of lists in prologComparing list element structures to each other in Prologchanging and removing lines from text file using swi-prologHow to read data from file into PrologSwi Prolog, Read file examples

How to know whether to write accidentals as sharps or flats?

How to search for Android apps without ads?

How would Japanese people react to someone refusing to say “itadakimasu” for religious reasons?

Digital signature that is only verifiable by one specific person

Converting 3x7 to a 1x7. Is it possible with only existing parts?

Manager wants to hire me; HR does not. How to proceed?

How do I run a script as sudo at boot time on Ubuntu 18.04 Server?

What is "dot" sign in •NO?

Explicit direct #include vs. Non-contractual transitive #include

Are there examples of rowers who also fought?

Is swap gate equivalent to just exchanging the wire of the two qubits?

How useful is the GRE Exam?

Why is Skinner so awkward in Hot Fuzz?

TiKZ won't graph 1/sqrt(x)

How did space travel spread through the galaxy?

...and then she held the gun

First occurrence in the Sixers sequence

Why are almost all the people in this orchestra recording wearing headphones with one ear on and one ear off?

The instant an accelerating object has zero speed, is it speeding up, slowing down, or neither?

How can I ping multiple IP addresses at the same time?

How to avoid offending original culture when making conculture inspired from original

Background for black and white chart

How can Caller ID be faked?

Leaving job close to major deadlines



How to ignore the first and last element on each line when reading from a text file in Prolog?


Why do some DCG test cases use assertion( Rest == [])?Reading a line from a file in GNU PrologProlog importing facts from a formatted text fileHow to read from file using see and putting the content into a list in Prolog?Prolog I/O reading file and extracting info to usereading files in PrologGetting max element from a list of lists in prologComparing list element structures to each other in Prologchanging and removing lines from text file using swi-prologHow to read data from file into PrologSwi Prolog, Read file examples






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








1















I need to read the contents of a fixed-format text file into a list of lists (LL) in Prolog but I want to exclude the first and last element on each line from the list for that line. The very first line of the input file includes the number of rows (number of lists in LL) and columns (number of elements per list in LL).
An example input file with 3 rows and 4 columns is



3 4
A B C D Cd
1 9 3 7 4 7
2 6 8 4 0 32
3 2 4 3 8 42
Ab 140 21 331 41 55


and I would like



LL = [[9,3,7,4],[6,8,4,0],[2,4,3,8]]


How can I exclude the first and last element on each line from LL?



I have tried reading the SWI-Prolog documentation and searching for relevant threads here, but I have been unsuccessful.



readAll( InStream, [W|L] ) :-
readWordNumber( InStream, W ), !,
readAll( InStream, L ).

readAll( InStream, [] ) :-
+readWordNumber(InStream,_).

lst_2_lst_of_lst([], _N, []).
lst_2_lst_of_lst(L, N, LL) :-
lst_2_lst_of_lst_helper(L, 1, N, LL).
lst_2_lst_of_lst_helper([H|T], N, N, [[H]|LL]):-
lst_2_lst_of_lst(T, N, LL).
lst_2_lst_of_lst_helper([H|T], N1 , N, [[H|TMP]|LL]):-
N2 is N1 + 1,
lst_2_lst_of_lst_helper(T, N2 , N, [TMP| LL]).



After calls to



...readAll(F,Input), ...
lst_2_lst_of_lst(Input, C, LL)


(C is 4, read in from first line of F, the text file)



My current result looks like this



LL = [[1,9 3 7 4 7,2,6 8 4 0 32],[3,2 4 3 8 42,Ab,140 21 331 41]]



and I would like it to look like this



LL = [[9,3,7,4],[6,8,4,0],[2,4,3,8]]









share|improve this question



















  • 1





    DCG is your friend. Perhaps an introduction is necessary. - Primer

    – Guy Coder
    Mar 25 at 8:31


















1















I need to read the contents of a fixed-format text file into a list of lists (LL) in Prolog but I want to exclude the first and last element on each line from the list for that line. The very first line of the input file includes the number of rows (number of lists in LL) and columns (number of elements per list in LL).
An example input file with 3 rows and 4 columns is



3 4
A B C D Cd
1 9 3 7 4 7
2 6 8 4 0 32
3 2 4 3 8 42
Ab 140 21 331 41 55


and I would like



LL = [[9,3,7,4],[6,8,4,0],[2,4,3,8]]


How can I exclude the first and last element on each line from LL?



I have tried reading the SWI-Prolog documentation and searching for relevant threads here, but I have been unsuccessful.



readAll( InStream, [W|L] ) :-
readWordNumber( InStream, W ), !,
readAll( InStream, L ).

readAll( InStream, [] ) :-
+readWordNumber(InStream,_).

lst_2_lst_of_lst([], _N, []).
lst_2_lst_of_lst(L, N, LL) :-
lst_2_lst_of_lst_helper(L, 1, N, LL).
lst_2_lst_of_lst_helper([H|T], N, N, [[H]|LL]):-
lst_2_lst_of_lst(T, N, LL).
lst_2_lst_of_lst_helper([H|T], N1 , N, [[H|TMP]|LL]):-
N2 is N1 + 1,
lst_2_lst_of_lst_helper(T, N2 , N, [TMP| LL]).



After calls to



...readAll(F,Input), ...
lst_2_lst_of_lst(Input, C, LL)


(C is 4, read in from first line of F, the text file)



My current result looks like this



LL = [[1,9 3 7 4 7,2,6 8 4 0 32],[3,2 4 3 8 42,Ab,140 21 331 41]]



and I would like it to look like this



LL = [[9,3,7,4],[6,8,4,0],[2,4,3,8]]









share|improve this question



















  • 1





    DCG is your friend. Perhaps an introduction is necessary. - Primer

    – Guy Coder
    Mar 25 at 8:31














1












1








1








I need to read the contents of a fixed-format text file into a list of lists (LL) in Prolog but I want to exclude the first and last element on each line from the list for that line. The very first line of the input file includes the number of rows (number of lists in LL) and columns (number of elements per list in LL).
An example input file with 3 rows and 4 columns is



3 4
A B C D Cd
1 9 3 7 4 7
2 6 8 4 0 32
3 2 4 3 8 42
Ab 140 21 331 41 55


and I would like



LL = [[9,3,7,4],[6,8,4,0],[2,4,3,8]]


How can I exclude the first and last element on each line from LL?



I have tried reading the SWI-Prolog documentation and searching for relevant threads here, but I have been unsuccessful.



readAll( InStream, [W|L] ) :-
readWordNumber( InStream, W ), !,
readAll( InStream, L ).

readAll( InStream, [] ) :-
+readWordNumber(InStream,_).

lst_2_lst_of_lst([], _N, []).
lst_2_lst_of_lst(L, N, LL) :-
lst_2_lst_of_lst_helper(L, 1, N, LL).
lst_2_lst_of_lst_helper([H|T], N, N, [[H]|LL]):-
lst_2_lst_of_lst(T, N, LL).
lst_2_lst_of_lst_helper([H|T], N1 , N, [[H|TMP]|LL]):-
N2 is N1 + 1,
lst_2_lst_of_lst_helper(T, N2 , N, [TMP| LL]).



After calls to



...readAll(F,Input), ...
lst_2_lst_of_lst(Input, C, LL)


(C is 4, read in from first line of F, the text file)



My current result looks like this



LL = [[1,9 3 7 4 7,2,6 8 4 0 32],[3,2 4 3 8 42,Ab,140 21 331 41]]



and I would like it to look like this



LL = [[9,3,7,4],[6,8,4,0],[2,4,3,8]]









share|improve this question
















I need to read the contents of a fixed-format text file into a list of lists (LL) in Prolog but I want to exclude the first and last element on each line from the list for that line. The very first line of the input file includes the number of rows (number of lists in LL) and columns (number of elements per list in LL).
An example input file with 3 rows and 4 columns is



3 4
A B C D Cd
1 9 3 7 4 7
2 6 8 4 0 32
3 2 4 3 8 42
Ab 140 21 331 41 55


and I would like



LL = [[9,3,7,4],[6,8,4,0],[2,4,3,8]]


How can I exclude the first and last element on each line from LL?



I have tried reading the SWI-Prolog documentation and searching for relevant threads here, but I have been unsuccessful.



readAll( InStream, [W|L] ) :-
readWordNumber( InStream, W ), !,
readAll( InStream, L ).

readAll( InStream, [] ) :-
+readWordNumber(InStream,_).

lst_2_lst_of_lst([], _N, []).
lst_2_lst_of_lst(L, N, LL) :-
lst_2_lst_of_lst_helper(L, 1, N, LL).
lst_2_lst_of_lst_helper([H|T], N, N, [[H]|LL]):-
lst_2_lst_of_lst(T, N, LL).
lst_2_lst_of_lst_helper([H|T], N1 , N, [[H|TMP]|LL]):-
N2 is N1 + 1,
lst_2_lst_of_lst_helper(T, N2 , N, [TMP| LL]).



After calls to



...readAll(F,Input), ...
lst_2_lst_of_lst(Input, C, LL)


(C is 4, read in from first line of F, the text file)



My current result looks like this



LL = [[1,9 3 7 4 7,2,6 8 4 0 32],[3,2 4 3 8 42,Ab,140 21 331 41]]



and I would like it to look like this



LL = [[9,3,7,4],[6,8,4,0],[2,4,3,8]]






prolog






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 25 at 6:05







quiconque

















asked Mar 25 at 4:10









quiconquequiconque

84




84







  • 1





    DCG is your friend. Perhaps an introduction is necessary. - Primer

    – Guy Coder
    Mar 25 at 8:31













  • 1





    DCG is your friend. Perhaps an introduction is necessary. - Primer

    – Guy Coder
    Mar 25 at 8:31








1




1





DCG is your friend. Perhaps an introduction is necessary. - Primer

– Guy Coder
Mar 25 at 8:31






DCG is your friend. Perhaps an introduction is necessary. - Primer

– Guy Coder
Mar 25 at 8:31













3 Answers
3






active

oldest

votes


















2














I would separate the issue of parsing the file and cleanup lines.
Let's say we have a predicate that actually captures lines of tokens.
Then the following could be applied:



cleanup([_,_|Data],Clean) :-
remove_last(Data,DataC),
maplist([[_|L],C]>>remove_last(L,C),DataC,Clean).
remove_last(L,C) :-
append(C,[_],L).


Capturing lines of tokens could be



readAll(InStream,[Line|Lines]) :-
read_a_line(InStream,Line),
readAll(InStream,Lines).
readAll(_InStream,[]).

read_a_line(F,L) :-
read_line_to_string(F,S),
S=end_of_file,
tokenize_atom(S,L).


To illustrate some of the IO facilities of SWI-Prolog, a quick test:



?- data(F),open_any(string(F),read,Stream,Close,[]),readAll(Stream,AllLines),cleanup(AllLines,Clean),Close.
F = "3 4nA B C D Cdn1 9 3 7 4 7n2 6 8 4 0 32n3 2 4 3 8 42nAb 140 21 331 41 55",
Stream = <stream>(0x7f37b039e5d0),
Close = close(<stream>(0x7f37b039e5d0)),
AllLines = [[3, 4], ['A', 'B', 'C', 'D', 'Cd'], [1, 9, 3, 7, 4, 7], [2, 6, 8, 4, 0|...], [3, 2, 4, 3|...], ['Ab', 140, 21|...]],
Clean = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]]


where data(F) actually binds F to the string you have in your example file.



Without lambda, we need an 'use once' predicate: for instance



cleanup([_,_|Data],Clean) :-
remove_last(Data,DataC),
maplist(remove_first_and_last,DataC,Clean).
%maplist([[_|L],C]>>remove_last(L,C),DataC,Clean).
remove_first_and_last([_|L],C) :-
append(C,[_],L).





share|improve this answer

























  • This works perfectly, thank you. I appreciate that it did not require adding a library, as I have not learned how to do that yet.

    – quiconque
    Mar 25 at 19:26












  • If possible, could you explain briefly what the >> operator does? I've found a reference in the SWI-Prolog documentation to (>>)/2 "Calls a copy of lambda" but I generally find this documentation very hard to understand, and this case is no exception.

    – quiconque
    Mar 25 at 19:28











  • Yes, the documentation is a bit terse. So, I'll add the equivalent code without lambda (library(yall) implements lambda expressions s efficiently, it's a fairly recent addition to SWI-Prolog)

    – CapelliC
    Mar 25 at 19:46


















1














Not absolutely certain that I understand your requirements. Your input looks a bit like tabular data, but it also looks a bit like a file format of some kind. Which one is it? How is it actually defined? What is the importance of the second row/line of your example input? Is "white space" the column separator? The questions can go on.



Here is how I will interpret your problem:



  • The first line of input has two integer values separated by whitespace; those are "row" and "column" count nrow and ncol.

  • The second row is not relevant (?).

  • Then, a number of rows with whitespace-separated columns with integers in them follow. For nrow lines, make a list nrow long:

    • skip the first column;

    • take the next ncol columns and put them in a list of integers.


  • skip the rest of input.

Writing this down is about 99% of the hard work (not saying it is hard, but for this problem, all of the "hardness" is in here).



Now you can go ahead and do the easy part: write the code. SWI-Prolog provides this great little library called dcg/basics. With it, I came up with this (in a hurry):



$ cat ignore.pl
:- use_module(library(dcg/basics)).

read_stuff_from_stream(Stuff, Stream) :-
phrase_from_stream(stuff(Stuff), Stream).

stuff(LL) -->
integer(Nrow), white, whites, integer(Ncol), blanks_to_nl, !,
string_without("n", _Skip_this_line), "n",
rows(Nrow, Ncol, LL),
remainder(_Skip_the_rest).

rows(0, _, []) --> !.
rows(Nrow, Ncol, [R|Rows]) --> succ(Nrow0, Nrow) ,
skip_column,
cols(Ncol, R),
string_without("n", _Skip_rest_of_line), "n", !,
rows(Nrow0, Ncol, Rows).

skip_column --> nonblanks(_Skip_this_column), white, whites.

cols(0, []) --> !.
cols(Ncol, [C|Cols]) --> succ(Ncol0, Ncol) ,
integer(C), white, whites, !,
cols(Ncol0, Cols).


It isn't "clean" code but it is a starting point. It works for the example you gave it.



3 4
A B C D Cd
1 9 3 7 4 7
2 6 8 4 0 32
3 2 4 3 8 42
Ab 140 21 331 41 55
$ swipl -q
?- [ignore].
true.

?- setup_call_cleanup(open('example.txt', read, In), read_stuff_from_stream(Stuff, In), close(In)).
In = <stream>(0x55f44e03de50),
Stuff = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]].


There is room for improvement in like 10 different directions. If you don't understand something, ask.






share|improve this answer























  • Your summary of the input file process is correct. Thank you for the comment on first writing down and clarifying the problem before starting to code; this method will definitely be helpful when approaching future coding problems.

    – quiconque
    Mar 25 at 19:21











  • @quiconque I knew how to do this long before I started programming. It is called "problem solving". If you are still learning it (and you are older than say 12 years old) you have missed the train.

    – User9213
    Mar 26 at 4:08


















1














Complete code using DCG.



:- use_module(library(dcg/basics), except([eos/2])). 

:- set_prolog_flag(double_quotes, codes).

parse(LL) -->
size(Rows,Columns),
header,
rows(Rows,Columns,LL),
footer.

size(Row,Columns) -->
integer(Row),
whites,
integer(Columns),
"n".

header -->
string_without("n",_),
"n".

rows(Rows0,Columns,[Item|Items]) -->
row(Columns,Item),
Rows is Rows0 - 1 ,
rows(Rows,Columns,Items).
rows(0,_Columns,[]) --> [].

row(Columns,Values) -->
integer(_), % Ignore first value
whites,
values(Columns,Values),
integer(_), % Ignore last value
"n".

values(Columns0,[Item|Items]) -->
value(Item),
Columns is Columns0 - 1 ,
values(Columns,Items).
values(0,[]) --> [].

value(Item) -->
integer(Item),
whites.

footer -->
rest_of_line, !.

rest_of_line -->
[_],
rest_of_line.
rest_of_line --> [].

readAll(LL) :-
phrase_from_file(parse(LL),'C:/ll.dat').



Test cases



:- begin_tests(data).

test(1) :-
Input = "c
3 4nc
A B C D Cdnc
1 9 3 7 4 7nc
2 6 8 4 0 32nc
3 2 4 3 8 42nc
Ab 140 21 331 41 55nc
",
string_codes(Input,Codes),
DCG = parse(LL),
phrase(DCG,Codes,Rest),
assertion( LL == [[9,3,7,4],[6,8,4,0],[2,4,3,8]] ),
assertion( Rest == [] ).

test(2) :-
Input_path = 'C:/ll.dat',
DCG = parse(LL),
phrase_from_file(DCG,Input_path),
assertion( LL == [[9,3,7,4],[6,8,4,0],[2,4,3,8]] ).

:- end_tests(data).



Example run of test cases



?- run_tests.
% PL-Unit: data .. done
% All 2 tests passed
true.



Example run



?- readAll(LL).
LL = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]].



When ever you process list you should consider using DCG (Primer).



The data is processed as character codes so the values for unification also have to be characters codes. People don't easily read character codes so Prolog has an option to turn double-quoted items into list of character codes. In the code "abc" is translated during compilation/consulting into [97,98,99]. This is done with a Prolog flag.



:- set_prolog_flag(double_quotes, codes).


Since using DCG is so common there is a library of predefined common predicates in dcg/basics in a module.



SWI Prolog has unit test.



To make it easier to format the input data for reading with unit test c is used.



The predicate that drives DCGs is phrase but it comes it two very common variations.



  1. phrase/2 is typically used when the data is not read from a file. I also find it useful when developing and testing DCGs because you can see the entire stream of values. When the data is processed as a list of character codes and the input is a string, you will typically find string_codes/2 used with phrase/2. This is demonstrated in test(1)


  2. phrase_from_file/2 is typically used when you have the DCG working and want to read the data directly from a file.



View unit test in SWI-Prolog debugger.



If you want to use the debugger with a test case using SWI-Prolog then you
start the debugger with



?- gtrace.
true.


Then run a specific test



[trace] ?- run_tests(data:1).





share|improve this answer

























  • Using succ(N0, N) instead of N0 is N - 1 for counting down has the nice property that it fails when it reaches 0. Try succ(X, 1), succ(X, 0), succ(X, -1) to see what I mean.

    – User9213
    Mar 25 at 10:01











  • @User9213 Thanks.

    – Guy Coder
    Mar 25 at 10:03











  • I do not understand your approach to testing. You can do most of what you normally do in the body using the head of the tests. The assertions especially keep me wondering what it is that makes them at all necessary.

    – User9213
    Mar 25 at 10:04











  • It is great you are writing tests. The question is, why are you writing them this way? In the documentation to PlUnit you have many examples and they don't look much like what you are doing. So I naturally assume you are doing something special, but I am not clever enough to understand what is this special thing you are doing?

    – User9213
    Mar 25 at 10:23






  • 1





    Not sure if you read my question, or if it was too badly written. Example of strange stuff that has no apparent reason to my limited mind. phrase(X, Y) and phrase(X, Y, Z), Z== [] seem to me to be the exactly same thing; but your code disagrees. Why?

    – User9213
    Mar 25 at 11:20











Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55331162%2fhow-to-ignore-the-first-and-last-element-on-each-line-when-reading-from-a-text-f%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























3 Answers
3






active

oldest

votes








3 Answers
3






active

oldest

votes









active

oldest

votes






active

oldest

votes









2














I would separate the issue of parsing the file and cleanup lines.
Let's say we have a predicate that actually captures lines of tokens.
Then the following could be applied:



cleanup([_,_|Data],Clean) :-
remove_last(Data,DataC),
maplist([[_|L],C]>>remove_last(L,C),DataC,Clean).
remove_last(L,C) :-
append(C,[_],L).


Capturing lines of tokens could be



readAll(InStream,[Line|Lines]) :-
read_a_line(InStream,Line),
readAll(InStream,Lines).
readAll(_InStream,[]).

read_a_line(F,L) :-
read_line_to_string(F,S),
S=end_of_file,
tokenize_atom(S,L).


To illustrate some of the IO facilities of SWI-Prolog, a quick test:



?- data(F),open_any(string(F),read,Stream,Close,[]),readAll(Stream,AllLines),cleanup(AllLines,Clean),Close.
F = "3 4nA B C D Cdn1 9 3 7 4 7n2 6 8 4 0 32n3 2 4 3 8 42nAb 140 21 331 41 55",
Stream = <stream>(0x7f37b039e5d0),
Close = close(<stream>(0x7f37b039e5d0)),
AllLines = [[3, 4], ['A', 'B', 'C', 'D', 'Cd'], [1, 9, 3, 7, 4, 7], [2, 6, 8, 4, 0|...], [3, 2, 4, 3|...], ['Ab', 140, 21|...]],
Clean = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]]


where data(F) actually binds F to the string you have in your example file.



Without lambda, we need an 'use once' predicate: for instance



cleanup([_,_|Data],Clean) :-
remove_last(Data,DataC),
maplist(remove_first_and_last,DataC,Clean).
%maplist([[_|L],C]>>remove_last(L,C),DataC,Clean).
remove_first_and_last([_|L],C) :-
append(C,[_],L).





share|improve this answer

























  • This works perfectly, thank you. I appreciate that it did not require adding a library, as I have not learned how to do that yet.

    – quiconque
    Mar 25 at 19:26












  • If possible, could you explain briefly what the >> operator does? I've found a reference in the SWI-Prolog documentation to (>>)/2 "Calls a copy of lambda" but I generally find this documentation very hard to understand, and this case is no exception.

    – quiconque
    Mar 25 at 19:28











  • Yes, the documentation is a bit terse. So, I'll add the equivalent code without lambda (library(yall) implements lambda expressions s efficiently, it's a fairly recent addition to SWI-Prolog)

    – CapelliC
    Mar 25 at 19:46















2














I would separate the issue of parsing the file and cleanup lines.
Let's say we have a predicate that actually captures lines of tokens.
Then the following could be applied:



cleanup([_,_|Data],Clean) :-
remove_last(Data,DataC),
maplist([[_|L],C]>>remove_last(L,C),DataC,Clean).
remove_last(L,C) :-
append(C,[_],L).


Capturing lines of tokens could be



readAll(InStream,[Line|Lines]) :-
read_a_line(InStream,Line),
readAll(InStream,Lines).
readAll(_InStream,[]).

read_a_line(F,L) :-
read_line_to_string(F,S),
S=end_of_file,
tokenize_atom(S,L).


To illustrate some of the IO facilities of SWI-Prolog, a quick test:



?- data(F),open_any(string(F),read,Stream,Close,[]),readAll(Stream,AllLines),cleanup(AllLines,Clean),Close.
F = "3 4nA B C D Cdn1 9 3 7 4 7n2 6 8 4 0 32n3 2 4 3 8 42nAb 140 21 331 41 55",
Stream = <stream>(0x7f37b039e5d0),
Close = close(<stream>(0x7f37b039e5d0)),
AllLines = [[3, 4], ['A', 'B', 'C', 'D', 'Cd'], [1, 9, 3, 7, 4, 7], [2, 6, 8, 4, 0|...], [3, 2, 4, 3|...], ['Ab', 140, 21|...]],
Clean = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]]


where data(F) actually binds F to the string you have in your example file.



Without lambda, we need an 'use once' predicate: for instance



cleanup([_,_|Data],Clean) :-
remove_last(Data,DataC),
maplist(remove_first_and_last,DataC,Clean).
%maplist([[_|L],C]>>remove_last(L,C),DataC,Clean).
remove_first_and_last([_|L],C) :-
append(C,[_],L).





share|improve this answer

























  • This works perfectly, thank you. I appreciate that it did not require adding a library, as I have not learned how to do that yet.

    – quiconque
    Mar 25 at 19:26












  • If possible, could you explain briefly what the >> operator does? I've found a reference in the SWI-Prolog documentation to (>>)/2 "Calls a copy of lambda" but I generally find this documentation very hard to understand, and this case is no exception.

    – quiconque
    Mar 25 at 19:28











  • Yes, the documentation is a bit terse. So, I'll add the equivalent code without lambda (library(yall) implements lambda expressions s efficiently, it's a fairly recent addition to SWI-Prolog)

    – CapelliC
    Mar 25 at 19:46













2












2








2







I would separate the issue of parsing the file and cleanup lines.
Let's say we have a predicate that actually captures lines of tokens.
Then the following could be applied:



cleanup([_,_|Data],Clean) :-
remove_last(Data,DataC),
maplist([[_|L],C]>>remove_last(L,C),DataC,Clean).
remove_last(L,C) :-
append(C,[_],L).


Capturing lines of tokens could be



readAll(InStream,[Line|Lines]) :-
read_a_line(InStream,Line),
readAll(InStream,Lines).
readAll(_InStream,[]).

read_a_line(F,L) :-
read_line_to_string(F,S),
S=end_of_file,
tokenize_atom(S,L).


To illustrate some of the IO facilities of SWI-Prolog, a quick test:



?- data(F),open_any(string(F),read,Stream,Close,[]),readAll(Stream,AllLines),cleanup(AllLines,Clean),Close.
F = "3 4nA B C D Cdn1 9 3 7 4 7n2 6 8 4 0 32n3 2 4 3 8 42nAb 140 21 331 41 55",
Stream = <stream>(0x7f37b039e5d0),
Close = close(<stream>(0x7f37b039e5d0)),
AllLines = [[3, 4], ['A', 'B', 'C', 'D', 'Cd'], [1, 9, 3, 7, 4, 7], [2, 6, 8, 4, 0|...], [3, 2, 4, 3|...], ['Ab', 140, 21|...]],
Clean = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]]


where data(F) actually binds F to the string you have in your example file.



Without lambda, we need an 'use once' predicate: for instance



cleanup([_,_|Data],Clean) :-
remove_last(Data,DataC),
maplist(remove_first_and_last,DataC,Clean).
%maplist([[_|L],C]>>remove_last(L,C),DataC,Clean).
remove_first_and_last([_|L],C) :-
append(C,[_],L).





share|improve this answer















I would separate the issue of parsing the file and cleanup lines.
Let's say we have a predicate that actually captures lines of tokens.
Then the following could be applied:



cleanup([_,_|Data],Clean) :-
remove_last(Data,DataC),
maplist([[_|L],C]>>remove_last(L,C),DataC,Clean).
remove_last(L,C) :-
append(C,[_],L).


Capturing lines of tokens could be



readAll(InStream,[Line|Lines]) :-
read_a_line(InStream,Line),
readAll(InStream,Lines).
readAll(_InStream,[]).

read_a_line(F,L) :-
read_line_to_string(F,S),
S=end_of_file,
tokenize_atom(S,L).


To illustrate some of the IO facilities of SWI-Prolog, a quick test:



?- data(F),open_any(string(F),read,Stream,Close,[]),readAll(Stream,AllLines),cleanup(AllLines,Clean),Close.
F = "3 4nA B C D Cdn1 9 3 7 4 7n2 6 8 4 0 32n3 2 4 3 8 42nAb 140 21 331 41 55",
Stream = <stream>(0x7f37b039e5d0),
Close = close(<stream>(0x7f37b039e5d0)),
AllLines = [[3, 4], ['A', 'B', 'C', 'D', 'Cd'], [1, 9, 3, 7, 4, 7], [2, 6, 8, 4, 0|...], [3, 2, 4, 3|...], ['Ab', 140, 21|...]],
Clean = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]]


where data(F) actually binds F to the string you have in your example file.



Without lambda, we need an 'use once' predicate: for instance



cleanup([_,_|Data],Clean) :-
remove_last(Data,DataC),
maplist(remove_first_and_last,DataC,Clean).
%maplist([[_|L],C]>>remove_last(L,C),DataC,Clean).
remove_first_and_last([_|L],C) :-
append(C,[_],L).






share|improve this answer














share|improve this answer



share|improve this answer








edited Mar 25 at 19:47

























answered Mar 25 at 13:23









CapelliCCapelliC

52.2k43263




52.2k43263












  • This works perfectly, thank you. I appreciate that it did not require adding a library, as I have not learned how to do that yet.

    – quiconque
    Mar 25 at 19:26












  • If possible, could you explain briefly what the >> operator does? I've found a reference in the SWI-Prolog documentation to (>>)/2 "Calls a copy of lambda" but I generally find this documentation very hard to understand, and this case is no exception.

    – quiconque
    Mar 25 at 19:28











  • Yes, the documentation is a bit terse. So, I'll add the equivalent code without lambda (library(yall) implements lambda expressions s efficiently, it's a fairly recent addition to SWI-Prolog)

    – CapelliC
    Mar 25 at 19:46

















  • This works perfectly, thank you. I appreciate that it did not require adding a library, as I have not learned how to do that yet.

    – quiconque
    Mar 25 at 19:26












  • If possible, could you explain briefly what the >> operator does? I've found a reference in the SWI-Prolog documentation to (>>)/2 "Calls a copy of lambda" but I generally find this documentation very hard to understand, and this case is no exception.

    – quiconque
    Mar 25 at 19:28











  • Yes, the documentation is a bit terse. So, I'll add the equivalent code without lambda (library(yall) implements lambda expressions s efficiently, it's a fairly recent addition to SWI-Prolog)

    – CapelliC
    Mar 25 at 19:46
















This works perfectly, thank you. I appreciate that it did not require adding a library, as I have not learned how to do that yet.

– quiconque
Mar 25 at 19:26






This works perfectly, thank you. I appreciate that it did not require adding a library, as I have not learned how to do that yet.

– quiconque
Mar 25 at 19:26














If possible, could you explain briefly what the >> operator does? I've found a reference in the SWI-Prolog documentation to (>>)/2 "Calls a copy of lambda" but I generally find this documentation very hard to understand, and this case is no exception.

– quiconque
Mar 25 at 19:28





If possible, could you explain briefly what the >> operator does? I've found a reference in the SWI-Prolog documentation to (>>)/2 "Calls a copy of lambda" but I generally find this documentation very hard to understand, and this case is no exception.

– quiconque
Mar 25 at 19:28













Yes, the documentation is a bit terse. So, I'll add the equivalent code without lambda (library(yall) implements lambda expressions s efficiently, it's a fairly recent addition to SWI-Prolog)

– CapelliC
Mar 25 at 19:46





Yes, the documentation is a bit terse. So, I'll add the equivalent code without lambda (library(yall) implements lambda expressions s efficiently, it's a fairly recent addition to SWI-Prolog)

– CapelliC
Mar 25 at 19:46













1














Not absolutely certain that I understand your requirements. Your input looks a bit like tabular data, but it also looks a bit like a file format of some kind. Which one is it? How is it actually defined? What is the importance of the second row/line of your example input? Is "white space" the column separator? The questions can go on.



Here is how I will interpret your problem:



  • The first line of input has two integer values separated by whitespace; those are "row" and "column" count nrow and ncol.

  • The second row is not relevant (?).

  • Then, a number of rows with whitespace-separated columns with integers in them follow. For nrow lines, make a list nrow long:

    • skip the first column;

    • take the next ncol columns and put them in a list of integers.


  • skip the rest of input.

Writing this down is about 99% of the hard work (not saying it is hard, but for this problem, all of the "hardness" is in here).



Now you can go ahead and do the easy part: write the code. SWI-Prolog provides this great little library called dcg/basics. With it, I came up with this (in a hurry):



$ cat ignore.pl
:- use_module(library(dcg/basics)).

read_stuff_from_stream(Stuff, Stream) :-
phrase_from_stream(stuff(Stuff), Stream).

stuff(LL) -->
integer(Nrow), white, whites, integer(Ncol), blanks_to_nl, !,
string_without("n", _Skip_this_line), "n",
rows(Nrow, Ncol, LL),
remainder(_Skip_the_rest).

rows(0, _, []) --> !.
rows(Nrow, Ncol, [R|Rows]) --> succ(Nrow0, Nrow) ,
skip_column,
cols(Ncol, R),
string_without("n", _Skip_rest_of_line), "n", !,
rows(Nrow0, Ncol, Rows).

skip_column --> nonblanks(_Skip_this_column), white, whites.

cols(0, []) --> !.
cols(Ncol, [C|Cols]) --> succ(Ncol0, Ncol) ,
integer(C), white, whites, !,
cols(Ncol0, Cols).


It isn't "clean" code but it is a starting point. It works for the example you gave it.



3 4
A B C D Cd
1 9 3 7 4 7
2 6 8 4 0 32
3 2 4 3 8 42
Ab 140 21 331 41 55
$ swipl -q
?- [ignore].
true.

?- setup_call_cleanup(open('example.txt', read, In), read_stuff_from_stream(Stuff, In), close(In)).
In = <stream>(0x55f44e03de50),
Stuff = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]].


There is room for improvement in like 10 different directions. If you don't understand something, ask.






share|improve this answer























  • Your summary of the input file process is correct. Thank you for the comment on first writing down and clarifying the problem before starting to code; this method will definitely be helpful when approaching future coding problems.

    – quiconque
    Mar 25 at 19:21











  • @quiconque I knew how to do this long before I started programming. It is called "problem solving". If you are still learning it (and you are older than say 12 years old) you have missed the train.

    – User9213
    Mar 26 at 4:08















1














Not absolutely certain that I understand your requirements. Your input looks a bit like tabular data, but it also looks a bit like a file format of some kind. Which one is it? How is it actually defined? What is the importance of the second row/line of your example input? Is "white space" the column separator? The questions can go on.



Here is how I will interpret your problem:



  • The first line of input has two integer values separated by whitespace; those are "row" and "column" count nrow and ncol.

  • The second row is not relevant (?).

  • Then, a number of rows with whitespace-separated columns with integers in them follow. For nrow lines, make a list nrow long:

    • skip the first column;

    • take the next ncol columns and put them in a list of integers.


  • skip the rest of input.

Writing this down is about 99% of the hard work (not saying it is hard, but for this problem, all of the "hardness" is in here).



Now you can go ahead and do the easy part: write the code. SWI-Prolog provides this great little library called dcg/basics. With it, I came up with this (in a hurry):



$ cat ignore.pl
:- use_module(library(dcg/basics)).

read_stuff_from_stream(Stuff, Stream) :-
phrase_from_stream(stuff(Stuff), Stream).

stuff(LL) -->
integer(Nrow), white, whites, integer(Ncol), blanks_to_nl, !,
string_without("n", _Skip_this_line), "n",
rows(Nrow, Ncol, LL),
remainder(_Skip_the_rest).

rows(0, _, []) --> !.
rows(Nrow, Ncol, [R|Rows]) --> succ(Nrow0, Nrow) ,
skip_column,
cols(Ncol, R),
string_without("n", _Skip_rest_of_line), "n", !,
rows(Nrow0, Ncol, Rows).

skip_column --> nonblanks(_Skip_this_column), white, whites.

cols(0, []) --> !.
cols(Ncol, [C|Cols]) --> succ(Ncol0, Ncol) ,
integer(C), white, whites, !,
cols(Ncol0, Cols).


It isn't "clean" code but it is a starting point. It works for the example you gave it.



3 4
A B C D Cd
1 9 3 7 4 7
2 6 8 4 0 32
3 2 4 3 8 42
Ab 140 21 331 41 55
$ swipl -q
?- [ignore].
true.

?- setup_call_cleanup(open('example.txt', read, In), read_stuff_from_stream(Stuff, In), close(In)).
In = <stream>(0x55f44e03de50),
Stuff = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]].


There is room for improvement in like 10 different directions. If you don't understand something, ask.






share|improve this answer























  • Your summary of the input file process is correct. Thank you for the comment on first writing down and clarifying the problem before starting to code; this method will definitely be helpful when approaching future coding problems.

    – quiconque
    Mar 25 at 19:21











  • @quiconque I knew how to do this long before I started programming. It is called "problem solving". If you are still learning it (and you are older than say 12 years old) you have missed the train.

    – User9213
    Mar 26 at 4:08













1












1








1







Not absolutely certain that I understand your requirements. Your input looks a bit like tabular data, but it also looks a bit like a file format of some kind. Which one is it? How is it actually defined? What is the importance of the second row/line of your example input? Is "white space" the column separator? The questions can go on.



Here is how I will interpret your problem:



  • The first line of input has two integer values separated by whitespace; those are "row" and "column" count nrow and ncol.

  • The second row is not relevant (?).

  • Then, a number of rows with whitespace-separated columns with integers in them follow. For nrow lines, make a list nrow long:

    • skip the first column;

    • take the next ncol columns and put them in a list of integers.


  • skip the rest of input.

Writing this down is about 99% of the hard work (not saying it is hard, but for this problem, all of the "hardness" is in here).



Now you can go ahead and do the easy part: write the code. SWI-Prolog provides this great little library called dcg/basics. With it, I came up with this (in a hurry):



$ cat ignore.pl
:- use_module(library(dcg/basics)).

read_stuff_from_stream(Stuff, Stream) :-
phrase_from_stream(stuff(Stuff), Stream).

stuff(LL) -->
integer(Nrow), white, whites, integer(Ncol), blanks_to_nl, !,
string_without("n", _Skip_this_line), "n",
rows(Nrow, Ncol, LL),
remainder(_Skip_the_rest).

rows(0, _, []) --> !.
rows(Nrow, Ncol, [R|Rows]) --> succ(Nrow0, Nrow) ,
skip_column,
cols(Ncol, R),
string_without("n", _Skip_rest_of_line), "n", !,
rows(Nrow0, Ncol, Rows).

skip_column --> nonblanks(_Skip_this_column), white, whites.

cols(0, []) --> !.
cols(Ncol, [C|Cols]) --> succ(Ncol0, Ncol) ,
integer(C), white, whites, !,
cols(Ncol0, Cols).


It isn't "clean" code but it is a starting point. It works for the example you gave it.



3 4
A B C D Cd
1 9 3 7 4 7
2 6 8 4 0 32
3 2 4 3 8 42
Ab 140 21 331 41 55
$ swipl -q
?- [ignore].
true.

?- setup_call_cleanup(open('example.txt', read, In), read_stuff_from_stream(Stuff, In), close(In)).
In = <stream>(0x55f44e03de50),
Stuff = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]].


There is room for improvement in like 10 different directions. If you don't understand something, ask.






share|improve this answer













Not absolutely certain that I understand your requirements. Your input looks a bit like tabular data, but it also looks a bit like a file format of some kind. Which one is it? How is it actually defined? What is the importance of the second row/line of your example input? Is "white space" the column separator? The questions can go on.



Here is how I will interpret your problem:



  • The first line of input has two integer values separated by whitespace; those are "row" and "column" count nrow and ncol.

  • The second row is not relevant (?).

  • Then, a number of rows with whitespace-separated columns with integers in them follow. For nrow lines, make a list nrow long:

    • skip the first column;

    • take the next ncol columns and put them in a list of integers.


  • skip the rest of input.

Writing this down is about 99% of the hard work (not saying it is hard, but for this problem, all of the "hardness" is in here).



Now you can go ahead and do the easy part: write the code. SWI-Prolog provides this great little library called dcg/basics. With it, I came up with this (in a hurry):



$ cat ignore.pl
:- use_module(library(dcg/basics)).

read_stuff_from_stream(Stuff, Stream) :-
phrase_from_stream(stuff(Stuff), Stream).

stuff(LL) -->
integer(Nrow), white, whites, integer(Ncol), blanks_to_nl, !,
string_without("n", _Skip_this_line), "n",
rows(Nrow, Ncol, LL),
remainder(_Skip_the_rest).

rows(0, _, []) --> !.
rows(Nrow, Ncol, [R|Rows]) --> succ(Nrow0, Nrow) ,
skip_column,
cols(Ncol, R),
string_without("n", _Skip_rest_of_line), "n", !,
rows(Nrow0, Ncol, Rows).

skip_column --> nonblanks(_Skip_this_column), white, whites.

cols(0, []) --> !.
cols(Ncol, [C|Cols]) --> succ(Ncol0, Ncol) ,
integer(C), white, whites, !,
cols(Ncol0, Cols).


It isn't "clean" code but it is a starting point. It works for the example you gave it.



3 4
A B C D Cd
1 9 3 7 4 7
2 6 8 4 0 32
3 2 4 3 8 42
Ab 140 21 331 41 55
$ swipl -q
?- [ignore].
true.

?- setup_call_cleanup(open('example.txt', read, In), read_stuff_from_stream(Stuff, In), close(In)).
In = <stream>(0x55f44e03de50),
Stuff = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]].


There is room for improvement in like 10 different directions. If you don't understand something, ask.







share|improve this answer












share|improve this answer



share|improve this answer










answered Mar 25 at 8:57









User9213User9213

90318




90318












  • Your summary of the input file process is correct. Thank you for the comment on first writing down and clarifying the problem before starting to code; this method will definitely be helpful when approaching future coding problems.

    – quiconque
    Mar 25 at 19:21











  • @quiconque I knew how to do this long before I started programming. It is called "problem solving". If you are still learning it (and you are older than say 12 years old) you have missed the train.

    – User9213
    Mar 26 at 4:08

















  • Your summary of the input file process is correct. Thank you for the comment on first writing down and clarifying the problem before starting to code; this method will definitely be helpful when approaching future coding problems.

    – quiconque
    Mar 25 at 19:21











  • @quiconque I knew how to do this long before I started programming. It is called "problem solving". If you are still learning it (and you are older than say 12 years old) you have missed the train.

    – User9213
    Mar 26 at 4:08
















Your summary of the input file process is correct. Thank you for the comment on first writing down and clarifying the problem before starting to code; this method will definitely be helpful when approaching future coding problems.

– quiconque
Mar 25 at 19:21





Your summary of the input file process is correct. Thank you for the comment on first writing down and clarifying the problem before starting to code; this method will definitely be helpful when approaching future coding problems.

– quiconque
Mar 25 at 19:21













@quiconque I knew how to do this long before I started programming. It is called "problem solving". If you are still learning it (and you are older than say 12 years old) you have missed the train.

– User9213
Mar 26 at 4:08





@quiconque I knew how to do this long before I started programming. It is called "problem solving". If you are still learning it (and you are older than say 12 years old) you have missed the train.

– User9213
Mar 26 at 4:08











1














Complete code using DCG.



:- use_module(library(dcg/basics), except([eos/2])). 

:- set_prolog_flag(double_quotes, codes).

parse(LL) -->
size(Rows,Columns),
header,
rows(Rows,Columns,LL),
footer.

size(Row,Columns) -->
integer(Row),
whites,
integer(Columns),
"n".

header -->
string_without("n",_),
"n".

rows(Rows0,Columns,[Item|Items]) -->
row(Columns,Item),
Rows is Rows0 - 1 ,
rows(Rows,Columns,Items).
rows(0,_Columns,[]) --> [].

row(Columns,Values) -->
integer(_), % Ignore first value
whites,
values(Columns,Values),
integer(_), % Ignore last value
"n".

values(Columns0,[Item|Items]) -->
value(Item),
Columns is Columns0 - 1 ,
values(Columns,Items).
values(0,[]) --> [].

value(Item) -->
integer(Item),
whites.

footer -->
rest_of_line, !.

rest_of_line -->
[_],
rest_of_line.
rest_of_line --> [].

readAll(LL) :-
phrase_from_file(parse(LL),'C:/ll.dat').



Test cases



:- begin_tests(data).

test(1) :-
Input = "c
3 4nc
A B C D Cdnc
1 9 3 7 4 7nc
2 6 8 4 0 32nc
3 2 4 3 8 42nc
Ab 140 21 331 41 55nc
",
string_codes(Input,Codes),
DCG = parse(LL),
phrase(DCG,Codes,Rest),
assertion( LL == [[9,3,7,4],[6,8,4,0],[2,4,3,8]] ),
assertion( Rest == [] ).

test(2) :-
Input_path = 'C:/ll.dat',
DCG = parse(LL),
phrase_from_file(DCG,Input_path),
assertion( LL == [[9,3,7,4],[6,8,4,0],[2,4,3,8]] ).

:- end_tests(data).



Example run of test cases



?- run_tests.
% PL-Unit: data .. done
% All 2 tests passed
true.



Example run



?- readAll(LL).
LL = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]].



When ever you process list you should consider using DCG (Primer).



The data is processed as character codes so the values for unification also have to be characters codes. People don't easily read character codes so Prolog has an option to turn double-quoted items into list of character codes. In the code "abc" is translated during compilation/consulting into [97,98,99]. This is done with a Prolog flag.



:- set_prolog_flag(double_quotes, codes).


Since using DCG is so common there is a library of predefined common predicates in dcg/basics in a module.



SWI Prolog has unit test.



To make it easier to format the input data for reading with unit test c is used.



The predicate that drives DCGs is phrase but it comes it two very common variations.



  1. phrase/2 is typically used when the data is not read from a file. I also find it useful when developing and testing DCGs because you can see the entire stream of values. When the data is processed as a list of character codes and the input is a string, you will typically find string_codes/2 used with phrase/2. This is demonstrated in test(1)


  2. phrase_from_file/2 is typically used when you have the DCG working and want to read the data directly from a file.



View unit test in SWI-Prolog debugger.



If you want to use the debugger with a test case using SWI-Prolog then you
start the debugger with



?- gtrace.
true.


Then run a specific test



[trace] ?- run_tests(data:1).





share|improve this answer

























  • Using succ(N0, N) instead of N0 is N - 1 for counting down has the nice property that it fails when it reaches 0. Try succ(X, 1), succ(X, 0), succ(X, -1) to see what I mean.

    – User9213
    Mar 25 at 10:01











  • @User9213 Thanks.

    – Guy Coder
    Mar 25 at 10:03











  • I do not understand your approach to testing. You can do most of what you normally do in the body using the head of the tests. The assertions especially keep me wondering what it is that makes them at all necessary.

    – User9213
    Mar 25 at 10:04











  • It is great you are writing tests. The question is, why are you writing them this way? In the documentation to PlUnit you have many examples and they don't look much like what you are doing. So I naturally assume you are doing something special, but I am not clever enough to understand what is this special thing you are doing?

    – User9213
    Mar 25 at 10:23






  • 1





    Not sure if you read my question, or if it was too badly written. Example of strange stuff that has no apparent reason to my limited mind. phrase(X, Y) and phrase(X, Y, Z), Z== [] seem to me to be the exactly same thing; but your code disagrees. Why?

    – User9213
    Mar 25 at 11:20















1














Complete code using DCG.



:- use_module(library(dcg/basics), except([eos/2])). 

:- set_prolog_flag(double_quotes, codes).

parse(LL) -->
size(Rows,Columns),
header,
rows(Rows,Columns,LL),
footer.

size(Row,Columns) -->
integer(Row),
whites,
integer(Columns),
"n".

header -->
string_without("n",_),
"n".

rows(Rows0,Columns,[Item|Items]) -->
row(Columns,Item),
Rows is Rows0 - 1 ,
rows(Rows,Columns,Items).
rows(0,_Columns,[]) --> [].

row(Columns,Values) -->
integer(_), % Ignore first value
whites,
values(Columns,Values),
integer(_), % Ignore last value
"n".

values(Columns0,[Item|Items]) -->
value(Item),
Columns is Columns0 - 1 ,
values(Columns,Items).
values(0,[]) --> [].

value(Item) -->
integer(Item),
whites.

footer -->
rest_of_line, !.

rest_of_line -->
[_],
rest_of_line.
rest_of_line --> [].

readAll(LL) :-
phrase_from_file(parse(LL),'C:/ll.dat').



Test cases



:- begin_tests(data).

test(1) :-
Input = "c
3 4nc
A B C D Cdnc
1 9 3 7 4 7nc
2 6 8 4 0 32nc
3 2 4 3 8 42nc
Ab 140 21 331 41 55nc
",
string_codes(Input,Codes),
DCG = parse(LL),
phrase(DCG,Codes,Rest),
assertion( LL == [[9,3,7,4],[6,8,4,0],[2,4,3,8]] ),
assertion( Rest == [] ).

test(2) :-
Input_path = 'C:/ll.dat',
DCG = parse(LL),
phrase_from_file(DCG,Input_path),
assertion( LL == [[9,3,7,4],[6,8,4,0],[2,4,3,8]] ).

:- end_tests(data).



Example run of test cases



?- run_tests.
% PL-Unit: data .. done
% All 2 tests passed
true.



Example run



?- readAll(LL).
LL = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]].



When ever you process list you should consider using DCG (Primer).



The data is processed as character codes so the values for unification also have to be characters codes. People don't easily read character codes so Prolog has an option to turn double-quoted items into list of character codes. In the code "abc" is translated during compilation/consulting into [97,98,99]. This is done with a Prolog flag.



:- set_prolog_flag(double_quotes, codes).


Since using DCG is so common there is a library of predefined common predicates in dcg/basics in a module.



SWI Prolog has unit test.



To make it easier to format the input data for reading with unit test c is used.



The predicate that drives DCGs is phrase but it comes it two very common variations.



  1. phrase/2 is typically used when the data is not read from a file. I also find it useful when developing and testing DCGs because you can see the entire stream of values. When the data is processed as a list of character codes and the input is a string, you will typically find string_codes/2 used with phrase/2. This is demonstrated in test(1)


  2. phrase_from_file/2 is typically used when you have the DCG working and want to read the data directly from a file.



View unit test in SWI-Prolog debugger.



If you want to use the debugger with a test case using SWI-Prolog then you
start the debugger with



?- gtrace.
true.


Then run a specific test



[trace] ?- run_tests(data:1).





share|improve this answer

























  • Using succ(N0, N) instead of N0 is N - 1 for counting down has the nice property that it fails when it reaches 0. Try succ(X, 1), succ(X, 0), succ(X, -1) to see what I mean.

    – User9213
    Mar 25 at 10:01











  • @User9213 Thanks.

    – Guy Coder
    Mar 25 at 10:03











  • I do not understand your approach to testing. You can do most of what you normally do in the body using the head of the tests. The assertions especially keep me wondering what it is that makes them at all necessary.

    – User9213
    Mar 25 at 10:04











  • It is great you are writing tests. The question is, why are you writing them this way? In the documentation to PlUnit you have many examples and they don't look much like what you are doing. So I naturally assume you are doing something special, but I am not clever enough to understand what is this special thing you are doing?

    – User9213
    Mar 25 at 10:23






  • 1





    Not sure if you read my question, or if it was too badly written. Example of strange stuff that has no apparent reason to my limited mind. phrase(X, Y) and phrase(X, Y, Z), Z== [] seem to me to be the exactly same thing; but your code disagrees. Why?

    – User9213
    Mar 25 at 11:20













1












1








1







Complete code using DCG.



:- use_module(library(dcg/basics), except([eos/2])). 

:- set_prolog_flag(double_quotes, codes).

parse(LL) -->
size(Rows,Columns),
header,
rows(Rows,Columns,LL),
footer.

size(Row,Columns) -->
integer(Row),
whites,
integer(Columns),
"n".

header -->
string_without("n",_),
"n".

rows(Rows0,Columns,[Item|Items]) -->
row(Columns,Item),
Rows is Rows0 - 1 ,
rows(Rows,Columns,Items).
rows(0,_Columns,[]) --> [].

row(Columns,Values) -->
integer(_), % Ignore first value
whites,
values(Columns,Values),
integer(_), % Ignore last value
"n".

values(Columns0,[Item|Items]) -->
value(Item),
Columns is Columns0 - 1 ,
values(Columns,Items).
values(0,[]) --> [].

value(Item) -->
integer(Item),
whites.

footer -->
rest_of_line, !.

rest_of_line -->
[_],
rest_of_line.
rest_of_line --> [].

readAll(LL) :-
phrase_from_file(parse(LL),'C:/ll.dat').



Test cases



:- begin_tests(data).

test(1) :-
Input = "c
3 4nc
A B C D Cdnc
1 9 3 7 4 7nc
2 6 8 4 0 32nc
3 2 4 3 8 42nc
Ab 140 21 331 41 55nc
",
string_codes(Input,Codes),
DCG = parse(LL),
phrase(DCG,Codes,Rest),
assertion( LL == [[9,3,7,4],[6,8,4,0],[2,4,3,8]] ),
assertion( Rest == [] ).

test(2) :-
Input_path = 'C:/ll.dat',
DCG = parse(LL),
phrase_from_file(DCG,Input_path),
assertion( LL == [[9,3,7,4],[6,8,4,0],[2,4,3,8]] ).

:- end_tests(data).



Example run of test cases



?- run_tests.
% PL-Unit: data .. done
% All 2 tests passed
true.



Example run



?- readAll(LL).
LL = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]].



When ever you process list you should consider using DCG (Primer).



The data is processed as character codes so the values for unification also have to be characters codes. People don't easily read character codes so Prolog has an option to turn double-quoted items into list of character codes. In the code "abc" is translated during compilation/consulting into [97,98,99]. This is done with a Prolog flag.



:- set_prolog_flag(double_quotes, codes).


Since using DCG is so common there is a library of predefined common predicates in dcg/basics in a module.



SWI Prolog has unit test.



To make it easier to format the input data for reading with unit test c is used.



The predicate that drives DCGs is phrase but it comes it two very common variations.



  1. phrase/2 is typically used when the data is not read from a file. I also find it useful when developing and testing DCGs because you can see the entire stream of values. When the data is processed as a list of character codes and the input is a string, you will typically find string_codes/2 used with phrase/2. This is demonstrated in test(1)


  2. phrase_from_file/2 is typically used when you have the DCG working and want to read the data directly from a file.



View unit test in SWI-Prolog debugger.



If you want to use the debugger with a test case using SWI-Prolog then you
start the debugger with



?- gtrace.
true.


Then run a specific test



[trace] ?- run_tests(data:1).





share|improve this answer















Complete code using DCG.



:- use_module(library(dcg/basics), except([eos/2])). 

:- set_prolog_flag(double_quotes, codes).

parse(LL) -->
size(Rows,Columns),
header,
rows(Rows,Columns,LL),
footer.

size(Row,Columns) -->
integer(Row),
whites,
integer(Columns),
"n".

header -->
string_without("n",_),
"n".

rows(Rows0,Columns,[Item|Items]) -->
row(Columns,Item),
Rows is Rows0 - 1 ,
rows(Rows,Columns,Items).
rows(0,_Columns,[]) --> [].

row(Columns,Values) -->
integer(_), % Ignore first value
whites,
values(Columns,Values),
integer(_), % Ignore last value
"n".

values(Columns0,[Item|Items]) -->
value(Item),
Columns is Columns0 - 1 ,
values(Columns,Items).
values(0,[]) --> [].

value(Item) -->
integer(Item),
whites.

footer -->
rest_of_line, !.

rest_of_line -->
[_],
rest_of_line.
rest_of_line --> [].

readAll(LL) :-
phrase_from_file(parse(LL),'C:/ll.dat').



Test cases



:- begin_tests(data).

test(1) :-
Input = "c
3 4nc
A B C D Cdnc
1 9 3 7 4 7nc
2 6 8 4 0 32nc
3 2 4 3 8 42nc
Ab 140 21 331 41 55nc
",
string_codes(Input,Codes),
DCG = parse(LL),
phrase(DCG,Codes,Rest),
assertion( LL == [[9,3,7,4],[6,8,4,0],[2,4,3,8]] ),
assertion( Rest == [] ).

test(2) :-
Input_path = 'C:/ll.dat',
DCG = parse(LL),
phrase_from_file(DCG,Input_path),
assertion( LL == [[9,3,7,4],[6,8,4,0],[2,4,3,8]] ).

:- end_tests(data).



Example run of test cases



?- run_tests.
% PL-Unit: data .. done
% All 2 tests passed
true.



Example run



?- readAll(LL).
LL = [[9, 3, 7, 4], [6, 8, 4, 0], [2, 4, 3, 8]].



When ever you process list you should consider using DCG (Primer).



The data is processed as character codes so the values for unification also have to be characters codes. People don't easily read character codes so Prolog has an option to turn double-quoted items into list of character codes. In the code "abc" is translated during compilation/consulting into [97,98,99]. This is done with a Prolog flag.



:- set_prolog_flag(double_quotes, codes).


Since using DCG is so common there is a library of predefined common predicates in dcg/basics in a module.



SWI Prolog has unit test.



To make it easier to format the input data for reading with unit test c is used.



The predicate that drives DCGs is phrase but it comes it two very common variations.



  1. phrase/2 is typically used when the data is not read from a file. I also find it useful when developing and testing DCGs because you can see the entire stream of values. When the data is processed as a list of character codes and the input is a string, you will typically find string_codes/2 used with phrase/2. This is demonstrated in test(1)


  2. phrase_from_file/2 is typically used when you have the DCG working and want to read the data directly from a file.



View unit test in SWI-Prolog debugger.



If you want to use the debugger with a test case using SWI-Prolog then you
start the debugger with



?- gtrace.
true.


Then run a specific test



[trace] ?- run_tests(data:1).






share|improve this answer














share|improve this answer



share|improve this answer








edited Mar 25 at 14:37

























answered Mar 25 at 9:12









Guy CoderGuy Coder

16.7k54489




16.7k54489












  • Using succ(N0, N) instead of N0 is N - 1 for counting down has the nice property that it fails when it reaches 0. Try succ(X, 1), succ(X, 0), succ(X, -1) to see what I mean.

    – User9213
    Mar 25 at 10:01











  • @User9213 Thanks.

    – Guy Coder
    Mar 25 at 10:03











  • I do not understand your approach to testing. You can do most of what you normally do in the body using the head of the tests. The assertions especially keep me wondering what it is that makes them at all necessary.

    – User9213
    Mar 25 at 10:04











  • It is great you are writing tests. The question is, why are you writing them this way? In the documentation to PlUnit you have many examples and they don't look much like what you are doing. So I naturally assume you are doing something special, but I am not clever enough to understand what is this special thing you are doing?

    – User9213
    Mar 25 at 10:23






  • 1





    Not sure if you read my question, or if it was too badly written. Example of strange stuff that has no apparent reason to my limited mind. phrase(X, Y) and phrase(X, Y, Z), Z== [] seem to me to be the exactly same thing; but your code disagrees. Why?

    – User9213
    Mar 25 at 11:20

















  • Using succ(N0, N) instead of N0 is N - 1 for counting down has the nice property that it fails when it reaches 0. Try succ(X, 1), succ(X, 0), succ(X, -1) to see what I mean.

    – User9213
    Mar 25 at 10:01











  • @User9213 Thanks.

    – Guy Coder
    Mar 25 at 10:03











  • I do not understand your approach to testing. You can do most of what you normally do in the body using the head of the tests. The assertions especially keep me wondering what it is that makes them at all necessary.

    – User9213
    Mar 25 at 10:04











  • It is great you are writing tests. The question is, why are you writing them this way? In the documentation to PlUnit you have many examples and they don't look much like what you are doing. So I naturally assume you are doing something special, but I am not clever enough to understand what is this special thing you are doing?

    – User9213
    Mar 25 at 10:23






  • 1





    Not sure if you read my question, or if it was too badly written. Example of strange stuff that has no apparent reason to my limited mind. phrase(X, Y) and phrase(X, Y, Z), Z== [] seem to me to be the exactly same thing; but your code disagrees. Why?

    – User9213
    Mar 25 at 11:20
















Using succ(N0, N) instead of N0 is N - 1 for counting down has the nice property that it fails when it reaches 0. Try succ(X, 1), succ(X, 0), succ(X, -1) to see what I mean.

– User9213
Mar 25 at 10:01





Using succ(N0, N) instead of N0 is N - 1 for counting down has the nice property that it fails when it reaches 0. Try succ(X, 1), succ(X, 0), succ(X, -1) to see what I mean.

– User9213
Mar 25 at 10:01













@User9213 Thanks.

– Guy Coder
Mar 25 at 10:03





@User9213 Thanks.

– Guy Coder
Mar 25 at 10:03













I do not understand your approach to testing. You can do most of what you normally do in the body using the head of the tests. The assertions especially keep me wondering what it is that makes them at all necessary.

– User9213
Mar 25 at 10:04





I do not understand your approach to testing. You can do most of what you normally do in the body using the head of the tests. The assertions especially keep me wondering what it is that makes them at all necessary.

– User9213
Mar 25 at 10:04













It is great you are writing tests. The question is, why are you writing them this way? In the documentation to PlUnit you have many examples and they don't look much like what you are doing. So I naturally assume you are doing something special, but I am not clever enough to understand what is this special thing you are doing?

– User9213
Mar 25 at 10:23





It is great you are writing tests. The question is, why are you writing them this way? In the documentation to PlUnit you have many examples and they don't look much like what you are doing. So I naturally assume you are doing something special, but I am not clever enough to understand what is this special thing you are doing?

– User9213
Mar 25 at 10:23




1




1





Not sure if you read my question, or if it was too badly written. Example of strange stuff that has no apparent reason to my limited mind. phrase(X, Y) and phrase(X, Y, Z), Z== [] seem to me to be the exactly same thing; but your code disagrees. Why?

– User9213
Mar 25 at 11:20





Not sure if you read my question, or if it was too badly written. Example of strange stuff that has no apparent reason to my limited mind. phrase(X, Y) and phrase(X, Y, Z), Z== [] seem to me to be the exactly same thing; but your code disagrees. Why?

– User9213
Mar 25 at 11:20

















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55331162%2fhow-to-ignore-the-first-and-last-element-on-each-line-when-reading-from-a-text-f%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript