读取文件并保存到列表

Read a file and save to a list

我有一个格式的文件:

3
1 2 3 4 5
4 5 6
1 6 2 4 6 7

第一行标识接下来的几行。这些行反过来只是一系列数字。我需要将其保存到可能如下所示的列表中:

N = 3,
Teams = [line(1, 2, 3, 4, 5), line(4, 5, 6), line(1, 6, 2, 4, 6, 7)].

到目前为止我正在尝试的是:

read_file(File, N, Lines) :-
    open(File, read, Stream),
    read_line_to_codes(Stream, Line),
    atom_codes(Atom, Line),
    atom_number(Atom, N),
    read_lines(Stream, N, Lines).

read_lines(Stream, N, Lines) :-
    ( N == 0 -> Lines = []
    ; N > 0  -> read_line(Stream, N, Line),
                Nm1 is N-1,
                read_lines(Stream, Nm1, RestLines),
                Lines = [Line | RestLines]).

read_line(Stream, N, line()) :-
    read_line_to_codes(Stream, Line),
    atom_codes(Atom, Line),
    atomic_list_concat([N | Atoms], ' ', Atom),
    maplist(atom_number, Atoms, []).

但我认为 atomic_list_concat([N | Atoms], ' ', Atom), 似乎有问题。这是我第一次接触序言,所以我不确定发生了什么。我该如何修复上面的代码?

我肯定会用 来解决这个问题。这里的想法是为您的输入创建一个简单的语法并使用它来解析文件。

:- use_module(library(dcg/basics)).

input(N, Teams) --> integer(N), blanks, teams(Teams).
teams([Team|Teams]) --> team(Team), blank, teams(Teams).
teams([]) --> [].

team([X|Xs]) --> integer(X), whites, team(Xs).
team([]) --> [].

dcg/basics 为我们提供了我们在这里使用的四个实用函数:blankblankswhitesinteger/1。这些解析包含换行符的空白 space、包含换行符的多个空白 space 和包含换行符的多个白色 space 字符 not 和整数。

语法说一个输入包含一个整数N,一个空行,然后是一些队。这些团队要么是一个团队,一个空白的团队,要么是更多的团队,否则我们就完成了。部署相同的想法来获得一个团队:我们要么有一个整数和一些 spaces 和一些更多的整数,要么我们就完成了。请注意 DCG 版本比字节处理方法更短、更具声明性!

使用起来也相当简单:

?- phrase_from_file(input(N, Teams), 'input.txt').
N = 3,
Teams = [[1, 2, 3, 4, 5], [4, 5, 6], [1, 6, 2, 4, 6, 7]] ;
false.

如果需要,您可以将其提升到实用谓词中:

parse(Filename, N, Teams) :- phrase_from_file(input(N, Teams), Filename).

?- parse('input.txt', N, Teams).
N = 3,
Teams = [[1, 2, 3, 4, 5], [4, 5, 6], [1, 6, 2, 4, 6, 7]] .

尽情享受吧!

编辑:我可能不会将其更改为return line(1,2,3,4,5), line(4,5,6), ...,因为您会发现处理可变元数结构很不愉快。但是如果你真的想要,你可以用这个代替 team//1 规则:

team(Team) --> team_list(TeamList), { Team =.. [list|TeamList] }.
team_list([X|Xs]) --> integer(X), whites, team_list(Xs).
team_list([]) --> [].

这里我们使用 univ (=..) 从列表中构建一个术语。同样,我不会在这里部署这个想法,因为您的处理将变得更加复杂而可能没有真正的收益。