2

DCG を使用して、文字列をスペースで区切られた 2 つの部分に分割しようとしています。たとえば、「abc def」は「abc」と「def」を返すはずです。プログラムとDCGは以下です。

main:-
    prompt(_, ''),
    repeat,
    read_line_to_codes(current_input, Codes),
    (
        Codes = end_of_file
    ->
        true
    ;
        processData(Codes),
        fail
    ).

processData(Codes):-
    (
        phrase(data(Part1, Part2), Codes)
    ->
        format('~s, ~s\n', [ Part1, Part2 ])
    ;
        format('Didn''t recognize data.\n')
    ).

data([ P1 | Part1 ], [ P2 | Part2 ]) --> [ P1 | Part1 ], spaces(_), [ P2 | Part2 ].
spaces([ S | S1 ]) --> [ S ], { code_type(S, space) }, (spaces(S1); "").

これは正しく動作します。しかし、[ P1 | Part1 ]&を入力しなければならないの[ P2 | Part2 ]は本当に冗長であることがわかりました。そこで、の定義で[ P1 | Part1 ]w/ Part1& 同様に w/のすべてのインスタンスを置き換えてみました。つまり、次のようになります。[ P2 | Part2 ]data

data(Part1, Part2) --> Part1, spaces(_), Part2.

入力するのははるかに簡単ですが、Arguments are not sufficiently instantiatedエラーが発生しました。したがって、バインドされていない変数は、DCG のコードのリストとして自動的に解釈されないようです。これを冗長にする他の方法はありますか?私の意図は、他のプログラミング言語で正規表現を使用するところに DCG を使用することです。

4

1 に答える 1

4

あなたの直感は正しいです。の変更されたバージョンを使用した DCG (少なくとも SWI-Prolog では、他のものにも適用する必要があります) の項拡張手順dataは、次のようになります。

?- listing(data). 

data(A, D, B, F) :-
    phrase(A, B, C),
    spaces(_, C, E),
    phrase(D, E, F).

ご覧のとおり、DCG ルールの変数Part1と一部は、リストではなく、再度の呼び出しに解釈されています。それらがリストとして扱われるようにするには、それらがリストであることを明示的に指定する必要があります。Part2phrase/3

より一般的な代替バージョンを提案できます。次の一連の DCG ルールを検討してください。

data([A|As]) --> 
    spaces(_), 
    chars([X|Xs]), 
    {atom_codes(A, [X|Xs])}, 
    spaces(_), 
    data(As).
data([]) --> [].

chars([X|Xs]) --> char(X), !, chars(Xs).
chars([]) --> [].

spaces([X|Xs]) --> space(X), !, spaces(Xs).
spaces([]) --> [].

space(X) --> [X], {code_type(X, space)}. 
char(X) --> [X], {\+ code_type(X, space)}.

一番上の最初の節を見てください。ルールは、data0 対多のスペース (カットのために可能な限り多く) との一致を試み、A次にコードからアトム ( )を構築するために 1 対多の非スペース文字との一致を試行し、次に 0 対多の一致を試みます。再びスペースを使用し、再帰して文字列内のアトムをさらに検索します ( As)。最終的に得られるのは、入力文字列にスペースなしで表示されたアトムのリストです。以下を使用して、このバージョンをコードに組み込むことができます。

processData(Codes) :-
    % convert the list of codes to a list of code lists of words
    (phrase(data(AtomList), Codes) ->
        % concatenate the atoms into a single one delimited by commas
        concat_atom(AtomList, ', ', Atoms),
        write_ln(Atoms)
    ;
        format('Didn''t recognize data.\n')
    ).

このバージョンでは、文字列の先頭と末尾にある場合でも、単語間の任意の数のスペースで文字列を分割します。

于 2011-05-24T00:55:20.170 に答える