【问题标题】:SWI-Prolog predicate for reading in lines from input file用于从输入文件中读取行的 SWI-Prolog 谓词
【发布时间】:2015-07-16 20:39:27
【问题描述】:

我正在尝试编写一个谓词来接受输入文件中的一行。每次使用它时,它应该给出下一行,直到它到达文件的末尾,此时它应该返回 false。像这样的:

database :-
    see('blah.txt'),
    loop,
    seen.

loop :-
    accept_line(Line),
    write('I found a line.\n'),
    loop.

accept_line([Char | Rest]) :-
    get0(Char),
    C =\= "\n", 
    !,
    accept_line(Rest).
accept_line([]).

显然这行不通。它适用于输入文件的第一行,然后无限循环。我可以看到我需要在某处有一些像“C =\= -1”这样的行来检查文件的结尾,但我看不到它会去哪里。

所以一个示例输入和输出可以是......

INPUT
this is
an example

OUTPUT
I found a line.
I found a line.

还是我这样做完全错了?也许有一个内置规则可以简单地做到这一点?

【问题讨论】:

    标签: file-io prolog swi-prolog


    【解决方案1】:

    在 SWI-Prolog 中,最优雅的方法是首先使用 DCG 来描述“线”的含义,然后使用 library(pio) 将 DCG 应用于文件。

    这样做的一个重要优势是,您可以轻松地将相同的 DCG 应用到具有phrase/2 的顶层查询上,并且无需创建文件来测试谓词。 p>

    DCG tutorial 解释了这种方法,您可以轻松地将其调整为适合您的用例。

    例如:

    :- use_module(library(pio)).
    
    :- set_prolog_flag(double_quotes, codes).
    
    lines --> call(eos), !.
    lines --> line, { writeln('I found a line.') }, lines.
    
    line --> ( "\n" ; call(eos) ), !.
    line --> [_], line.
    
    eos([], []).
    

    示例用法:

    ?- phrase_from_file(lines, 'blah.txt').
    I found a line.
    I found a line.
    true.
    

    示例用法,使用相同的DCG直接从字符代码解析而不使用文件:

    ?- phrase(lines, "test1\ntest2").
    I found a line.
    I found a line.
    true.
    

    这种方法可以很容易地扩展到解析更复杂的文件内容。

    【讨论】:

    • 一个好建议(+1)。我对 SWI-Prolog 的 library(pio) 仍然存在的唯一问题是它仍然没有实现从非重新定位流中读取。所以,我不能将它用于标准输入,必须使用read_line_to_codesread_pending_inputread_string+string_codes 才能使用DCG。由于我似乎是唯一需要此功能的人,所以与其抱怨,我也许可以自己做......
    • @Boris: library(pio) 缺少很多东西:它也应该适用于设置为charsdouble_quotes,更通用如this 等。这更像是一个political 问题。一种免费软件的祝福。
    • @false 我无法完全按照。该库无法与 SWI7 一起使用的技术原因究竟是什么?
    • @Boris:喜欢:SWI7 中不支持chars,因为支持codes
    • @Boris:喜欢:改变所有这些机制所依赖的基本假设(参见上面的链接)。你无法战胜随机变化的单人系统。
    【解决方案2】:

    如果您想阅读代码列表,请参阅 library(readutil),尤其是 read_line_to_codes/2,它可以满足您的需求。

    您当然可以使用character I/O primitives,但至少使用ISO 谓词。 “爱丁堡式” I/O 已被弃用,至少对于 SWI-Prolog 而言。那么:

    获取线(L):- 获取代码(C), get_line_1(C,L)。 get_line_1(-1, []) :- !. %EOF get_line_1(0'\n, []) :- !. % 停产 get_line_1(C, [C|Cs]) :- 获取代码(C1), get_line_1(C1,Cs)。

    这当然是很多不必要的代码;只需使用 read_line_to_codes/2 和 library(readutil) 中的其他谓词。

    自从strings 被引入Prolog 以来,出现了一些新的漂亮的阅读方式。例如,要读取所有输入并将其拆分为行,您可以这样做:

    read_string(user_input, _, S),
    split_string(S, "\n", "", Lines)
    

    请参阅read_string/5 中的示例以逐行阅读。

    附言。删除 seeseen 等。改为:

    setup_call_cleanup(打开(文件名,读取,在), read_string(In, N, S), % 或任何你需要做的阅读 逼近))

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-06
      • 2011-08-21
      • 1970-01-01
      • 1970-01-01
      • 2011-11-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多