一种非常干净的方法是使用 DCG,例如CapelliC 的答案。像他一样,使用library(pio)
Ulrich Neumerkel 的漂亮方法,例如在 SWI-Prolog 中找到的,您可以将 DCG 和phrase_from_file/2
以下解决方案结合起来:
:- use_module(library(pio)).
... --> []|[_], ... .
file_pattern_pos(File, Pattern, Pos) :-
phrase_from_file(( ...,
lazy_list_character_count(Pos),
Pattern,
...
),
File).
这是从文档中phrase_from_file/2
的代码示例逐字获取的,刚刚添加lazy_list_character_count//1
。与其他 DCG 答案不同,它在回溯时生成所有解决方案。所以有了这个文件:
$ cat banana.txt
banana
Antananarivo
你从顶层得到:
?- file_pattern_pos("banana.txt", "ana", Pos).
Pos = 1 ;
Pos = 3 ;
Pos = 10 ;
Pos = 12 ;
false.
列出单个字符的所有位置:
?- bagof(P, file_pattern_pos("banana.txt", "a", P), Ps).
Ps = [1, 3, 5, 10, 12, 14].
这个解决方案很好,因为只需查看文档中的代码示例即可轻松获得phrase_from_file/2
。但是,在下面的评论中指出了两个问题:
- 效率问题;
- Using
lazy_list_character_count//1
意味着您不能将其与phrase/2
.
正如评论中指出的那样,可以解决效率问题:
... --> [].
... --> [_], ... .
另一个问题更严重。毕竟,可能有必要计算消耗的字符数。例如:
span(N) --> span_(0, N).
span_(N, N) --> [].
span_(N0, N) --> [_],
{ N1 is N0 + 1
},
span_(N1, N).
现在,我们可以从顶层编写:
?- phrase_from_file(( span(Pos), "ana", ... ), "banana.txt").
Pos = 1 ;
Pos = 3 ;
Pos = 10 ;
Pos = 12 ;
false.
或者,使用phrase/2
:
?- phrase((span(P), "ana", ...), "banana").
P = 1 ;
P = 3 ;
false.