我是 Prolog 新手,并且一直在将字符串解析为列表。我有一串表格
1..2...3..4
我希望将其转换为看起来像的列表
[1, _, _, 2, _, _, _, 3, _, _, 4]
我怎样才能实现这个功能?
我是 Prolog 新手,并且一直在将字符串解析为列表。我有一串表格
1..2...3..4
我希望将其转换为看起来像的列表
[1, _, _, 2, _, _, _, 3, _, _, 4]
我怎样才能实现这个功能?
另一种解决方案是使用 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).
使用“字符串”(实际上只是代码列表)对 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 以更高级的符号打印匿名变量 (_),否则它应该是您需要的相同结果。
另一种方式..利用 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 或点,那么谓词应该会失败。
描述字符串中的字符与列表元素之间关系的谓词可以是:
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
从字符的整数值中减去,所以你可以写而不是使用 number_codes/2 Digit is DigitChar - 0'0
。
根据 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