2013-08-14 2 views
1

Je suis un débutant Prolog et je suis bloqué à l'analyse d'une chaîne à une liste. J'ai une chaîne de la formeconvertir la chaîne à la liste dans prolog

1..2...3..4 

Je souhaite la transformer en une liste qui ressemble à

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

Comment puis-je obtenir cette fonctionnalité?

+0

Ces chiffres uniques sont-ils entre les points ou les entiers? En d'autres termes, est-ce que "12.23' va à '[1, 2, _, 2, 3]' ou '[12, _, 23]'? –

+0

Ils sont à un seul chiffre. Donc 12.23 devient [1, 2, _, 2, 3] –

Répondre

2

Une autre solution consiste à utiliser des DCG. Le code est simple:

digit(N) --> 
    [ D ], { member(D, ""), 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). 

Test sur SWI-Prolog avec "string" (qui est en fait une liste de codes):

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

Et avec un atome (qui est juste converti en codes avant d'utiliser le même prédicat):

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

imprime SWI-Prolog des variables anonymes (_) dans une notation peu, mais colombophile sinon il devrait être le même résultat dont vous avez besoin.

0

Un prédicat qui décrit la relation entre un personnage dans votre chaîne et un élément de la liste pourrait être:

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 

Les premiers contrôles clause si le caractère est en effet un chiffre et il convertit à un nombre entier. Vous pouvez également simplement soustraire 0'0 de la valeur entière du caractère, donc au lieu d'utiliser number_codes/2, vous pouvez écrire Digit is DigitChar - 0'0.

Vous devriez pouvoir utiliser maplist/3 puis, selon le manuel gnou Prolog:

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

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

yes 

mais il ne fonctionne pas sur mon système (ancienne version de Prolog gnu peut-être?), Donc au lieu:

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 
1

Encore une autre façon .. tirer parti du fait que les numéros ascii pour 0..9 sont connus/fixes, alors aucune conversion de type ou des vérifications sont nécessaires, juste des soustractions.

% 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). 

Exécution:

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

Edit: a oublié de dire que cela fonctionne parce que les chaînes sont représentées sous forme d'une liste de numéros de ascii, si la chaîne "" est représentée en interne comme [48,49,50 51,52,53,54,55,56,57].

Onechar fait le calcul pour 1 de ces éléments de la liste, puis maplist appelle le même prédicat sur tous les éléments de la liste.

Edit 2: la 2ème règle était à l'origine:

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

C'est trop généreux - probablement si l'entrée ne contient pas 0,9 ou un point, le prédicat devrait échouer.

+0

Vous devriez vraiment utiliser la notation '0'' au lieu des codes ascii directs. C'est pareil, juste plus facile à lire (pas de nombres magiques). –