如何避免Prolog DCG解析数字网格时产生额外结果?
DCG解析数字网格时避免末尾空列表的解决方法
问题场景
使用SWI-Prolog的library(dcg/basic)编写DCG,将数字网格解析为行列表(每行是数字列表),原代码如下:
input([]) --> eos. input([Line|Lines]) --> line(Line), input(Lines). line([]) --> eol. line([Num|Nums]) --> whites, number(Num), line(Nums).
运行时发现解析结果末尾会追加额外的空列表,根源是eol(换行)和eos(输入结束)都能匹配输入末尾,导致最后一行被额外解析出空行。
通用解决思路
核心是明确行的定义:行要么是「非空数字列表 + 换行符」(中间行),要么是「非空数字列表 + 输入结束」(最后一行),禁止匹配无意义的空行。具体可以通过两种方式实现:
方案1:调整line规则,只匹配非空行并兼容换行/输入结束
先定义匹配非空数字序列的辅助规则,再让line规则明确匹配「非空数字序列 + 换行/输入结束」:
% 匹配非空的数字列表 numbers([Num|Nums]) --> whites, number(Num), rest_numbers(Nums). % 匹配后续的数字(可以为空) rest_numbers([]) --> []. rest_numbers([Num|Nums]) --> whites, number(Num), rest_numbers(Nums). % 匹配一行:非空数字列表 + 换行 或 输入结束 line(Line) --> numbers(Line), (eol ; eos). % 输入解析规则:若干行 + 输入结束 input([]) --> eos. input([Line|Lines]) --> line(Line), input(Lines).
方案2:拆分input规则,区分中间行和最后一行
直接在input规则里明确:中间行必须带换行,最后一行直接结束于输入末尾,同时确保所有行都是非空的:
% 匹配非空数字列表 line([Num|Nums]) --> whites, number(Num), rest_numbers(Nums). rest_numbers([]) --> []. rest_numbers([Num|Nums]) --> whites, number(Num), rest_numbers(Nums). % 最后一行:非空行 + 输入结束 input([Line]) --> line(Line), eos. % 中间行:非空行 + 换行 + 剩余输入 input([Line|Lines]) --> line(Line), eol, input(Lines).
关键说明
两种方案都通过禁止空行匹配解决了末尾空列表的问题:
- 方案1更灵活,兼容输入末尾有无换行的情况;
- 方案2逻辑更直观,明确区分中间行和最后一行的终止条件。
不需要直接操作差异列表,通过调整DCG规则的匹配条件即可解决问题。
内容的提问来源于stack exchange,提问作者Suskeyhose
相关产品推荐
相关产品推荐

