segunda-feira, 24 de outubro de 2016

Quem faz também desfaz...

Vamos fazer o exercício inverso da encriptação: dado um texto encriptado de acordo com um dado método refazer o texto original. Vamos fazer o exercício para cada um dos três métodos de que falámos.

Separação Pares - Ímpares

Este parece ser um caso trivial. Divididos o texto ao meio e depois tiramos alternadamente os caracteres de cada uma das componentes.
def desencripta_1(texto):
    # divide ao meio e separa
    meio = len(texto)//2
    pares = texto[:meio]
    impares = texto[meio:]
    # constrói texto
    novo_texto = ''
    for i in range(meio):
        novo_texto = novo_texto + pares[i] + impares[i]
    return novo_texto
Acontece que se testarmos com vários exemplos verificamos que nalguns casos o resultado não é o esperado. Não precisamos de reflectir muito para verificar que o problema acontece quando o texto tem um número ímpar da caracteres. Neste caso, o número de elementos na posição par é superior em uma unidade do número de elementos nas posições ímpares. Temos pois que ter cuidado quando fazemos a divisão ao meio, diferente em cada um dos casos. Resolvida esta questão uma solução será:
def desencripta_12(texto):
    # divide ao meio e separa
    comp = len(texto)
    meio, imp = divmod(comp,2)
    pares = texto[:meio]
    impares = texto[meio+imp:]
    # constrói texto
    novo_texto = ''
    for i in range(meio):
        novo_texto = novo_texto + pares[i] + impares[i]
    if imp:
        novo_texto = novo_texto + texto[meio]
    return novo_texto
Como se pode ver usamos a operação divido que nos permite obter as duas componentes através do mecanismo de desempacotamento:
meio,imp = divmod(com,2)
O nome imp estará associado ao objecto 1 (se texto tiver comprimento ímpar) ou ao objecto 0 (caso tenha comprimento par).

Distância Fixa

Neste método, se um caractere é deslocado n posições para a frente na codificação, então na descodificação cada caractere deve ser deslocado n posições para … trás!
def desencripta_2(texto_encriptado,chave):
    alfabeto = 'abcdefghijklmnopqrstuvwxyz '
    texto_normal = ''
    for car in texto_encriptado:
        indice = alfabeto.find(car) 
        texto_normal = texto_normal + alfabeto[(indice - chave)%len(alfabeto)]
    return texto_normal
Assumimos um alfabeto co mas 26 letras minúsculas mais o espaço em branco, mas a solução pode ser adaptada a qualquer alfabeto sem problemas.

Chave Aleatória

Este caso aparenta ser o mais complexo. Vejamos se é verdade. Comecemos por mostrar o código que permite definir uma chave e encriptar um texto:
def encripta_3(texto, alfabeto,chave):
    #chave = define_chave(alfabeto)
    novo_texto = ''
    for car in texto:
        ind = alfabeto.index(car)
        novo_texto = novo_texto + chave[ind]    
    return novo_texto

import random

def define_chave(alfabeto):
    simbolos = alfabeto
    chave = ''
    for car in alfabeto:
        novo_simb = random.choice(simbolos)
        ind = simbolos.index(novo_simb)
        simbolos = simbolos[:ind] + simbolos[ind+1:]
        chave = chave + novo_simb    
    return chave
Como a correspondência é um para um, se, por exemplo, a “b” no texto original corresponde “h” na chave então quando encontramos no texto codificado um “h” devemos ter um “b” no texto original. Afinal a solução não é assim tão complexa:
def desencripta_3(texto_encriptado,alfabeto,chave):
    texto_normal = ''
    for car in texto_encriptado:
        indice = chave.find(car) 
        texto_normal = texto_normal + alfabeto[indice]
    return texto_normal
Mas se pensarmos um pouco mais no que dissemos sobre a correspondência um a um, chegamos à conclusão que codificar e descodificar são o mesmo processo pelo que apenas precisamos de um programa. Dito de outro modo:
def desencripta_31(texto,alfabeto,chave):
    return encripta_3(texto,chave,alfabeto)
E pronto. Divirta-se a escrever variantes das soluções propostas. Por exemplo, usando sempre o alfabeto como parâmetro.

Sem comentários:

Enviar um comentário