将字符串转换为prolog中的列表

时间:2013-08-14 06:32:30

标签: prolog

我是Prolog的新手,我坚持将字符串解析为列表。 我有一个表格

的字符串
1..2...3..4

我希望将其转换为类似

的列表
[1, _, _, 2, _, _, _, 3, _, _, 4]

如何实现此功能?

3 个答案:

答案 0 :(得分:2)

另一种解决方案是使用DCG。代码很简单:

digit(N) -->
    [ D ], { member(D, "0123456789"), number_codes(N, [D]) }.

dot(_) --> ".".

token(T) --> digit(T).
token(T) --> dot(T).

tokens([T|Ts]) --> token(T), tokens(Ts).
tokens([]) --> "".

parse_codes(In, Out):-
    phrase(tokens(Out), In, "").

parse_atom(In, Out):-
    atom_codes(In, Codes),
    parse_codes(Codes, Out).

使用“string”(实际上只是代码列表)对SWI-Prolog进行测试:

?- parse_codes("1..24.4", Out).
Out = [1, _G992, _G995, 2, 4, _G1070, 4] .

使用原子(在使用相同的谓词之前刚刚转换为代码):

?- parse_atom('1..22.4', Out).
Out = [1, _G971, _G974, 2, 2, _G1049, 4] .

SWI-Prolog以比特代表符号打印​​匿名变量(_),否则它应该是您需要的相同结果。

答案 1 :(得分:1)

另一种方式..利用0..9的ascii数字已知/固定的事实,然后不需要类型转换或检查,只需减去。

% case 1: char is in decimal range 0-9, ie ascii 48,49,50,51,52,53,54,55,56,57
% so eg. char 48 returns integer 0
onechar(Char, Out) :-
    between(48, 57, Char),
    Out is Char -48.

% case 2: case 1 failed, dot '.' is ascii 46, use anonymous variable
onechar(46, _).

% execution
go(InString, OutList) :-
    maplist(onechar, InString, OutList).

执行:

?- go("1..2...3..4", X).
X = [1, _G5638, _G5641, 2, _G5650, _G5653, _G5656, 3, _G5665, _G5668, 4]

编辑:忘了说这是有效的,因为字符串表示为ascii数字列表,因此字符串“0123456789”在内部表示为[48,49,50,51,52,53,54,55,56, 57]。

onechar为这些列表项中的1个执行计算,然后maplist在所有列表项上调用相同的谓词。

编辑2:第二条规则最初是:

% case 2: case 1 failed, output is an anon variable
onechar(_, _).

这太慷慨了 - 大概如果输入不包含0.9或一个点,那么谓词应该失败。

答案 2 :(得分:0)

描述字符串中的字符与列表元素之间关系的谓词可以是:

char_to_el(DigitChar, Digit) :- % a character between '0' and '9'
    DigitChar >= 0'0, DigitChar =< 0'9,
    number_codes(Digit, [DigitChar]).
char_to_el(0'., _). % the element is the '.' characther

第一个子句检查字符是否确实是一个数字并将其转换为整数。您也可以简单地从字符的整数值中减去0'0,因此您可以编写Digit is DigitChar - 0'0而不是使用number_codes / 2。

根据gnu prolog手册,您应该可以使用maplist / 3:

| ?- maplist(char_to_el, "1..2...3..4", L).

L = [1,_,_,2,_,_,_,3,_,_,4]

yes

但它在我的系统上不起作用(可能是旧的gnu prolog版本?),所以相反:

str_to_list([], []).
str_to_list([C|Cs], [E|Es]) :-
    char_to_el(C, E),
    str_to_list(Cs, Es).

| ?- str_to_list("1..2...3..4", L).

L = [1,_,_,2,_,_,_,3,_,_,4]

yes