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;
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
add a comment |
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
1
DCG is your friend. Perhaps an introduction is necessary. - Primer
– Guy Coder
Mar 25 at 8:31
add a comment |
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
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
prolog
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
add a comment |
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
add a comment |
3 Answers
3
active
oldest
votes
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).
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
add a comment |
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
andncol
. - 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 listnrow
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.
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
add a comment |
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.
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)
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).
Usingsucc(N0, N)
instead ofN0 is N - 1
for counting down has the nice property that it fails when it reaches 0. Trysucc(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. Theassertion
s 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)
andphrase(X, Y, Z), Z== []
seem to me to be the exactly same thing; but your code disagrees. Why?
– User9213
Mar 25 at 11:20
|
show 2 more comments
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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).
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
add a comment |
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).
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
add a comment |
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).
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).
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
add a comment |
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
add a comment |
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
andncol
. - 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 listnrow
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.
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
add a comment |
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
andncol
. - 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 listnrow
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.
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
add a comment |
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
andncol
. - 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 listnrow
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.
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
andncol
. - 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 listnrow
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.
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
add a comment |
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
add a comment |
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.
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)
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).
Usingsucc(N0, N)
instead ofN0 is N - 1
for counting down has the nice property that it fails when it reaches 0. Trysucc(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. Theassertion
s 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)
andphrase(X, Y, Z), Z== []
seem to me to be the exactly same thing; but your code disagrees. Why?
– User9213
Mar 25 at 11:20
|
show 2 more comments
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.
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)
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).
Usingsucc(N0, N)
instead ofN0 is N - 1
for counting down has the nice property that it fails when it reaches 0. Trysucc(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. Theassertion
s 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)
andphrase(X, Y, Z), Z== []
seem to me to be the exactly same thing; but your code disagrees. Why?
– User9213
Mar 25 at 11:20
|
show 2 more comments
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.
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)
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).
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.
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)
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).
edited Mar 25 at 14:37
answered Mar 25 at 9:12
Guy CoderGuy Coder
16.7k54489
16.7k54489
Usingsucc(N0, N)
instead ofN0 is N - 1
for counting down has the nice property that it fails when it reaches 0. Trysucc(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. Theassertion
s 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)
andphrase(X, Y, Z), Z== []
seem to me to be the exactly same thing; but your code disagrees. Why?
– User9213
Mar 25 at 11:20
|
show 2 more comments
Usingsucc(N0, N)
instead ofN0 is N - 1
for counting down has the nice property that it fails when it reaches 0. Trysucc(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. Theassertion
s 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)
andphrase(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
assertion
s 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
assertion
s 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
|
show 2 more comments
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
1
DCG is your friend. Perhaps an introduction is necessary. - Primer
– Guy Coder
Mar 25 at 8:31