2

我正在尝试使用 DCG 将字符串拆分为由空格分隔的两部分。例如,'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 规则的变量Part1Part2部分已被解释为phrase/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)}.

看一下顶部的第一个子句;该data规则现在尝试匹配 0 对多的空格(尽可能多,因为剪切),然后是一对多的非空格字符以A从代码构造一个原子 ( ),然后是 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 回答