基于 DCG 的解决方案
我想在现有的解决方案中添加一个基于 DCG 的解决方案。
DCG的优势
使用 DCG 完成此任务有几个主要优势:
- 您可以轻松地以交互方式测试您的解析器,而无需修改单独的文件。
- 一个足够通用的 DCG 可用于解析和生成测试数据。
- 了解这种方法对于更复杂的解析任务可能会派上用场,这些任务不符合 CSV 等预定格式。
预赛
以下代码假定设置:
:- set_prolog_flag(double_quotes, chars)。
我推荐这个设置,因为它使 DCG 的工作更具可读性。
积木:token//1
我们从令牌含义的简短定义开始:
令牌(T)-->
铝(L),
token_(Ls),
!, % 单一解:最长匹配
{ atom_chars(T, [L|Ls]) }。
alnum(A) --> [A], { char_type(A, alnum) }。
token_([L|Ls]) --> alnum(L),token_(Ls)。
令牌_([])-> []。
示例查询
这里有一些例子:
?- 短语(令牌(T),“黄金”)。
T = '黄金'。
?- 短语(令牌(T),“2”)。
T = '2'。
?- 短语(token(T), "GOLD 2" )。
假的。
最后一个示例清楚地表明空格不能成为令牌的一部分。
空白
我们将以下序列视为空白:
空格-> []。
空格——>空格,空格。
空间 --> [S], { char_type(S, space) }。
解决方案
因此,由空格分隔的标记序列是:
令牌([])-> []。
标记([T|Ts]) --> 标记(T)、空格、标记(Ts)。
就是这样!
我们现在可以使用 Ulrich Neumerkel 的远见卓识将这个 DCG 透明地应用于文件library(pio)
:
这里是wumpus.data
:
$猫wumpus.data
黄金 3 2
乌姆普斯 3 3
坑 2 1
坑 3 4
使用phrase_from_file/2
将 DCG 应用于文件,我们得到:
?-phrase_from_file(令牌(Ts),'wumpus.data')。
Ts = ['GOLD','3','2','WUMPUS','3','3','PIT','2','1','PIT','3','4' ] .
从这样的令牌列表中,很容易得出必要的数据,例如再次使用 DCG:
数据([])-> []。
数据([D|Ds])-> 数据_(D),数据(Ds)。
数据_(黄金(X,Y))-> ['黄金'],坐标(X,Y)。
数据_(wumpus(X,Y))-> ['WUMPUS'],坐标(X,Y)。
数据_(坑(X,Y))-> ['PIT'],坐标(X,Y)。
坐标(X,Y)-> atom_number(X),atom_number(Y)。
atom_number(N) --> [A], { atom_number(A, N) }。
我们可以一起使用这些 DCG 来:
- 标记文件或给定的字符列表
- 解析令牌以创建结构化数据。
示例查询:
?-phrase_from_file(tokens(Ts), 'wumpus.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)]。
有关这种通用机制的更多信息,请参阅dcg。
1请注意,SWI-Prolog 附带一个过时的版本library(pio)
,它不适用于double_quotes
设置为 chars
. 如果您想在 SWI-Prolog 中试用,请直接使用 Ulrich 提供的版本。