如何将文件中的数据读入Prolog
我正在使用SWI Prolog创建Wumpus World项目。我应该从一个.txt文件中读取黄金、矿坑和Wumpus的位置,该文件如下所示:如何将文件中的数据读入Prolog,prolog,wumpus-world,dcg,Prolog,Wumpus World,Dcg,我正在使用SWI Prolog创建Wumpus World项目。我应该从一个.txt文件中读取黄金、矿坑和Wumpus的位置,该文件如下所示: GOLD 3 2 WUMPUS 3 3 PIT 2 1 PIT 3 4 其中单词表示对象,第一个数字表示对象的x位置,第二个数字表示对象的y位置。我知道如何打开文件并从中读取,我只是不知道如何告诉我的程序GOLD 3 2意味着GOLD需要位于(3,2)。您需要打开文件,读取其中的行,然后将每行拆分为您想要使用的术语。然后,您可以
GOLD 3 2
WUMPUS 3 3
PIT 2 1
PIT 3 4
其中单词表示对象,第一个数字表示对象的x位置,第二个数字表示对象的y位置。我知道如何打开文件并从中读取,我只是不知道如何告诉我的程序GOLD 3 2意味着GOLD需要位于(3,2)。您需要打开文件,读取其中的行,然后将每行拆分为您想要使用的术语。然后,您可以将这些术语放在某个变量中或
assert/1
将它们放入动态数据库中。在下面的示例中,我使用动态谓词location/3
将它们断言到数据库中:
:- dynamic location/3.
load(File) :-
setup_call_cleanup(
open(File, read, Stream),
load_loop(Stream),
close(Stream)
).
load_loop(Stream) :-
read_line_to_string(Stream, String),
(String == end_of_file ->
true
;
split_string(String, " ", " ", [ItemS, XS, YS]),
atom_string(Item, ItemS),
term_string(X, XS),
term_string(Y, YS),
assertz(location(Item, X, Y)),
load_loop(Stream)
).
show_locations :-
forall(location(Item, X, Y),
format('~p is at (~d, ~d)~n', [Item, X, Y])).
假设您的输入在wumpus.txt中,那么这将为您提供:
bash-3.2$ swipl -l wumpus.pl
'GOLD' is at (3, 2)
'WUMPUS' is at (3, 3)
'PIT' is at (2, 1)
'PIT' is at (3, 4)
考虑使用,免费读取和解析文件。我将您的示例放入一个文件wumpus.txt
:
$ cat wumpus.txt
GOLD 3 2
WUMPUS 3 3
PIT 2 1
PIT 3 4
库文档中有一些代码示例,下面是一个简单的示例,直接从顶层开始:
?- use_module(library(csv)).
true.
?- csv_read_file("wumpus.txt", World, [separator(0' ), functor(location)]),
forall(member(L, World), assertz(L)).
World = [location('GOLD', 3, 2), location('WUMPUS', 3, 3), location('PIT', 2, 1), location('PIT', 3, 4)].
重要:分隔符是空格字符的方法是添加选项location(0')
。0'
后和右括号前的空格是有效的
现在,数据库中有一个表,location/3
,它的类型作为第一个参数,坐标作为第二个和第三个参数
我想,你将如何使用这是另一个问题。现在你可以问,“我在哪里有金子”:
或者“我在哪里有坑”
基于DCG的解决方案
我想在现有解决方案的基础上添加一个基于DCG的解决方案
DCGs的优势
使用DCGs执行此任务有几个主要优点:
- 您可以轻松地以交互方式测试解析器,而无需修改单独的文件
- 一个足够通用的DCG可以用来解析和生成测试数据
- 了解此方法可能有助于更复杂的解析任务,这些任务不适合ECSV等预定格式
phrase\u from\u file/2
将DCG应用于该文件,我们得到:
?- phrase_from_file(tokens(Ts), 'wumpus.data').
Ts = ['GOLD', '3', '2', 'WUMPUS', '3', '3', 'PIT', '2', '1', 'PIT', '3', '4'] .
?-来自_文件的短语_(令牌(Ts),'wumpus.data')。
Ts=['GOLD','3','2','WUMPUS','3','3','PIT','2','1','PIT','3','4']。
从这样的令牌列表中,很容易导出必要的数据,例如再次使用aDCG:
data([]) --> [].
data([D|Ds]) --> data_(D), data(Ds).
data_(gold(X,Y)) --> ['GOLD'], coords(X, Y).
data_(wumpus(X,Y)) --> ['WUMPUS'], coords(X, Y).
data_(pit(X,Y)) --> ['PIT'], coords(X, Y).
coords(X, Y) --> atom_number(X), atom_number(Y).
atom_number(N) --> [A], { atom_number(A, N) }.
数据([])-->[]。
数据([D|Ds])-->数据(D),数据(Ds)。
数据(黄金(X,Y))-->['gold'],坐标(X,Y)。
数据(wumpus(X,Y))-->['wumpus',],坐标(X,Y)。
数据(pit(X,Y))-->['pit'],坐标(X,Y)。
坐标(X,Y)-->原子数(X),原子数(Y)。
原子数(N)->[A],{atom_数(A,N)}。
我们可以将这些DCG一起用于:
1请注意,SWI Prolog附带的过时的
库(pio)
版本不适用于设置为字符的双引号。如果您想在SWI Prolog中尝试此功能,请直接使用Ulrich提供的版本。回答正确(+1)。在SWI Prolog中有库(csv)
,这使得读取表格数据非常容易。请参阅我的答案。如果load\u loop/1
中出现问题,这很容易导致文件句柄泄漏。例如,创建不符合预期格式的wumpus.data
,并尝试以下查询作为测试用例:?-重复,加载('wumpus.data'),false。
。这很快就会抛出:错误:资源不足:max\u文件
。使用setup\u call\u cleanup/3
在所有情况下安全关闭文件!
?- phrase(token(T), "GOLD").
T = 'GOLD'.
?- phrase(token(T), "2").
T = '2'.
?- phrase(token(T), "GOLD 2").
false.
spaces --> [].
spaces --> space, spaces.
space --> [S], { char_type(S, space) }.
tokens([]) --> [].
tokens([T|Ts]) --> token(T), spaces, tokens(Ts).
$ cat wumpus.data
GOLD 3 2
WUMPUS 3 3
PIT 2 1
PIT 3 4
?- phrase_from_file(tokens(Ts), 'wumpus.data').
Ts = ['GOLD', '3', '2', 'WUMPUS', '3', '3', 'PIT', '2', '1', 'PIT', '3', '4'] .
data([]) --> [].
data([D|Ds]) --> data_(D), data(Ds).
data_(gold(X,Y)) --> ['GOLD'], coords(X, Y).
data_(wumpus(X,Y)) --> ['WUMPUS'], coords(X, Y).
data_(pit(X,Y)) --> ['PIT'], coords(X, Y).
coords(X, Y) --> atom_number(X), atom_number(Y).
atom_number(N) --> [A], { atom_number(A, N) }.
?- phrase_from_file(tokens(Ts), 'wumpus.data'),
phrase(data(Ds), Ts).
Ts = ['GOLD', '3', '2', 'WUMPUS', '3', '3', 'PIT', '2', '1'|...],
Ds = [gold(3, 2), wumpus(3, 3), pit(2, 1), pit(3, 4)] .