Prolog unable to writeln elements with carriage return

时间:2019-03-19 15:03:06

标签: prolog

I have trouble printing a list using writeln when it contains an element with a carriage return. Here is the code obtained from Learn Prolog Now!

%% Read text file into list of strings and numbers
readAll(InStream, []) :-
    at_end_of_stream(InStream), !.

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

%% read a white-space separated text or number
readWordNumber(InStream, W) :-
    get_code(InStream, Char),
    checkCharAndReadRest(Char, Chars, InStream),
    codes2NumOrWord(W, Chars).

%% Convert list of codes into a number if possible to string otherwise
codes2NumOrWord(N, Chars) :-
    atom_codes(W, Chars),
    atom_number(W, N), !.

codes2NumOrWord(W, Chars) :-
    atom_codes(W, Chars).

%% Source: Learn Prolog Now!   
checkCharAndReadRest(10, [], _) :- !.

checkCharAndReadRest(32, [], _) :- !.

checkCharAndReadRest(9, [], _) :- !.   

checkCharAndReadRest(-1, [], _) :- !.

checkCharAndReadRest(Char, [Char|Chars], InStream) :-
    get_code(InStream, NextChar),
    checkCharAndReadRest(NextChar, Chars, InStream).

Performing writeln(List) will not print the entire list. Specifically, everything before the last carriage return in the list will be ignored and only the elements after that is printed. Furthermore, it seems to not even write the correct thing most of the time.

For instance, something like this:

Source3 4 5 12 275
DEMAND 200 100 300

will print out something like this:

,DEMAND,200,100,300]

Naturally, I think the solution is to filter out /r, but I am not entirely sure how to do this. I am also interested in why this actually happens?

2 个答案:

答案 0 :(得分:1)

根据操作系统的不同,换行符可以使用换行符(ASCII 10),回车符(ASCII 13)或回车符后跟换行符。要解决所有这些情况,请添加以下子句(作为谓词的第一个):

checkCharAndReadRest(13, [], InStream) :- !,
    (   peek_code(InStream, 10) ->
        get_code(InStream, 10)
    ;   true
    ).

使用CR + LF行尾的内容创建data.txt文件:

Source3 4 5 12 275
DEMAND 200 100 300

礼物:

?- open('data.txt', read, S), readAll(S, L).
S = <stream>(0x7fb55ed7d690),
L = ['Source3', 4, 5, 12, 275, 'DEMAND', 200, 100, 300].

或者,正如您提到的,使用writeln/1编写读取令牌的列表(请注意,这不是标准谓词!):

?- open('data.txt', read, S), readAll(S, L), writeln(L).
[Source3,4,5,12,275,DEMAND,200,100,300]
S = <stream>(0x7fb5600e9a90),
L = ['Source3', 4, 5, 12, 275, 'DEMAND', 200, 100, 300].

答案 1 :(得分:0)

My current solution is to simply check if NextChar==13 and skip it.

checkCharAndReadRest(Char, [Char|Chars], InStream) :-
    get_code(InStream, NextChar),
    (   NextChar\=13
    ->  checkCharAndReadRest(NextChar, Chars, InStream)
    ;   get_code(InStream, NextChar2),
        checkCharAndReadRest(NextChar2, Chars, InStream)
    ).

I am sure someone else can do better...