2

こんにちは、入力ファイルから特定の文字を見つけてその位置を出力するコードを作成しようとしていましたが、「私が見つけた同様の問題の助けを借りて」出てきたものです

process2(Text,POS):-
    open('houses.txt', read, In),
    get_char(In, Char1),
    find(Char1, In,Text,POS),
    close(In).

find(Text,In, Text, 0).
find(Char,In,Text,POS) :-
    POS is POS1 +1,
    get_char(In, Char2),
    find(Char2,In,Text,POS1).

ただし、コンパイラは次のエラーをスローします: エラー: is/2: 引数が十分にインスタンス化されていません

4

4 に答える 4

2

入力を処理するときは、常に最初に DCG を考慮してください。

:- use_module(ライブラリ(pio) )。

process3(ファイル、テキスト、POS) :-phrase_from_file(find(テキスト、POS)、ファイル)。

find(Text, [P|Ps]) -->
    lazy_list_character_count (P)、テキスト、!、
    find(テキスト、Ps)。
検索 (テキスト、Ps) --> [_]、検索 (テキスト、Ps)。
find(_Text, []) --> [].

これは、入力文字列のすべての位置を見つけます。

?- process3('/home/carlo/.swiplrc', `file`, P).
P = [51, 174, 254, 452, 549, 1977, 2106, 3682, 4033|...] ;
false.

ボリスが提案したように編集すると、カットにより正当な解決策が削除される可能性があります。というわけでカット無しバージョンです。

find(_Text, []) --> [].
find(Text, [P|Ps]) -->
    lazy_list_character_count(P), Text,
    find(Text, Ps).
find(Text, Ps) --> \+Text, [_], find(Text, Ps).
于 2016-03-27T18:36:14.093 に答える
1

低レベルの算術演算の代わりに CLP(FD) 制約を使用するだけの場合、これは期待どおりに機能します。

:- use_module(library(clpfd)).

find(Text, In, Text, 0).
find(Char, In, Text, POS) :-
        POS #= POS1 + 1,
        get_char(In, Char2),
        find(Char2,In,Text, POS1).

CLP(FD) バージョンの利点は、これが末尾再帰であることです。これは、直感的に実行したことでもあります。

また、ファイルを処理するときsetup_call_cleanup/3は、さらに良いことをお勧めします。library(pio)(注: SICStus Prolog では、Prolog フラグdouble_quotesを に設定しchars、DCG を使用してファイルを文字として処理できます! これに興味がある場合は、SWI でのサポートを求めてロビー活動を行ってください!)

これは残して、コードの残りの (終了) 問題を演習として修正します。

于 2016-03-27T20:04:46.027 に答える
0

SWI-Prolog を使用することにコミットしている場合は、より単純なケースでテキストを操作するために文字列を使用できます。この場合、たとえば、を使用してストリームからファイルを読み取りIn(質問にあるように) read_string/3、 を使用してその中の部分文字列のすべての出現位置を見つけるだけで十分sub_string/5です。

setup_call_cleanup(open(File, read, In),
                   read_string(In, _, File_contents),
                   close(In)),
sub_string(File_contents, Pos, _Length, _After, Substr)

それでおしまい。Posの 0 ベースの位置になりSubstrます。文字を検索するには、長さ 1 の文字列を使用するだけです。最も優れている点の 1 つは、sub_string/5部分的に重複する部分文字列を正しく処理できることです。

?- sub_string("banana", Pos, _, _, "ana").
Pos = 1 ;
Pos = 3 ;
false.

のより標準的な対応物sub_string/5sub_atom/5で、セマンティクスは と同じですsub_string/5が、アトムを取ります。すべての Prolog 実装で利用できるはずです。

?- sub_atom(banana, Pos, _, _, ana).
Pos = 1 ;
Pos = 3 ;
false.

ファイル全体をコードに読み取った後、 と を使用するだけatom_codes/2ですsub_atom/5。ただし、これは少し無駄です。

ファイルの内容でより複雑なことをしなければならなくなったら、DCG などの使用に移ることができます。通常は不要なlibrary(pio)読み取りプリミティブの使用に戻ります。get_charただし、上記でリンクした文字列に関するマニュアルのセクションを読むことを強くお勧めします。

于 2016-03-28T20:06:00.747 に答える