Предполагая, что это простой шифр замены, о котором мы говорим (и просто для удовольствия), я попробую его. Следует отметить, что это совершенно не проверено.
Я собираюсь настроить это в общем виде, чтобы вы могли сказать что-то вроде:
substitution_cipher( CipherExpr , CipherResult , Expr , Result , Key ).
Мы возьмем за правило, что зашифрованный материал представлен атомами, так что вы можете сказать что-то вроде этого:
substitution_cipher( ping + pong + fun , ignip , Expr , Sum , Key ) .
И получить ожидаемые результаты.
So...
Во-первых, вам нужен набор (дискретный, уникальный) символов, найденных в зашифрованном тексте:
character_set( Expr , Charset ) :-
setof( C , A^Cs^( atoms_in_expression( Expr , A ) , atom_chars(A,Cs) , member(C,Cs) ) , Charset ) .
atom_in_expression( Expr , Value ) :- atom(Expr) .
atom_in_expression( Expr , Value ) :-
Expr =.. [ _ , Left , Right ] ,
(
values( Left , Value )
;
values( Right, Value
) .
Вышеупомянутое просматривает дерево синтаксического анализа выражения, подобного a * b + c * d
, находя каждый из листовых узлов (атомов), разлагая их на символы, которые их составляют. setof/3
гарантирует, что результирующий список будет отсортирован и уникален.
Как только вы это сделаете, вам понадобится способ сгенерировать все возможные ключи (key == сопоставление между символом и цифрой). Мы хотим иметь возможность сказать что-то вроде
generate_key( [a,b,c] , Key )
и вернуться
Key = [a:1,b:2,c:3]
и Т. Д.
So:
generate_key( Charset , Key ) :-
generate_key( Charset , [] , Key ) .
generate_key( [] , Key , Key ) . % when we've exhausted the character set, we're done.
generate_key( [C|Cs] , Acc , Key ) :- % otherwise...for each character
digit(D) , % find a digit
\+ member( _:D , Acc ) , % that hasn't yet been used
generate_key( Cs , [C:D|Acc] , Key ) % map it to the character and recurse down.
.
digit(D) :- between(0,9,X) , atom_number(D,X).
Тогда вам нужен способ декодировать выражение шифра, например
ping + pong + fun
и [попытаться] превратить его обратно в правильные числа. Это не сильно отличается от обхода дерева синтаксического анализа и перечисления атомов конечных узлов, но здесь нам нужно вернуть их в числовую форму.
Если выражение является атомом, мы
- разложить его на составляющие его символы,
- используя наш ключ, сопоставьте каждый символ с соответствующей цифрой,
затем мы превращаем этот список цифр обратно в число
декодировать(Ключ, CipherExpr, PlainExpr):- atom(CipherExpression), atom_chars(CipherExpression,Cs), findall(D, (member(C,Cs), member(C:D,Key) -> true; D=C) , Ds ), число_символов ( PlainExpr , Ds ) .
Общий случай прост. Инфиксное выражение вроде ping + pong
на самом деле является термином пролога +(ping,pong)
. Мы:
- Разложите инфиксный термин, например
ping + pong
, на оператор (+
) и его левое и правое подвыражения.
- Затем мы рекурсивно декодируем левое и правое подвыражения
Наконец, мы собираем выражение [decoded].
декодировать(Ключ, CipherExpr, PlainExpr) :- CipherExpr =.. [Op,L,R] , декодировать(L,L1) , декодировать(R,R1) , PlainExpr =.. [Op,L1,R1] .
Затем вы можете собрать все это вместе:
substitition_cipher( CipherExpr , CipherResult , PlainExpr , PlainResult , Key ) :-
character_set( CipherExpr = CipherResult , Charset ) ,
generate_key( Charset, Key ) ,
decode( Key , CipherExpr , PlainExpr ) ,
decode( Key , CipherResult , PlainResult ) ,
PlainResult =:= PlainExpr
.
person
Nicholas Carey
schedule
19.05.2015