我正在尝试使用DCG将字符串拆分为由空格分隔的两个部分。例如。 'abc def'应该给我回“abc”& “高清”。该计划& 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
&的所有实例。同样在[ P2 | Part2 ]
的定义中有data
,即以下内容。
data(Part1, Part2) --> Part1, spaces(_), Part2.
键入起来要容易得多,但这给了我一个Arguments are not sufficiently instantiated
错误。因此,看起来未绑定的变量不会自动解释为DCG中的代码列表。还有其他方法可以减少这种冗长吗?我的目的是使用DCG,我会在其他编程语言中使用正则表达式。
答案 0 :(得分:4)
你的直觉是正确的;使用修改后的data
版本,DCG的术语扩展程序(至少在SWI-Prolog中,但应该适用于其他人)提供以下内容:
?- listing(data).
data(A, D, B, F) :-
phrase(A, B, C),
spaces(_, C, E),
phrase(D, E, F).
正如您所看到的,DCG规则的变量Part1
和Part2
部分已被解释为再次调用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')
).
这个版本将字符串分开,单词之间有任意数量的空格,即使它们出现在字符串的开头和结尾。