sábado, 17 de outubro de 2015

Codifica e descodifica

[Problema 3.18 (dos apontamentos)] Um método muito simples para codificar/descodificar um texto baseia-se na ideia de usar uma chave de substituição. Uma variante básica do método consiste em substituir uma letra por outra que se encontre a uma certa distância dela. Por exemplo, se a distância for 2, então o c substitui o a, o d substitui o b e assim sucessivamente. Vamos escrever um programa que dado um texto e um inteiro que representa a distância, devolve o texto encriptado de acordo com essa distância.

Uma maneira de pensar a solução remete para o padrão ciclo-acumulador: usamos uma variável onde vai sendo acumulado o texto codificado, sendo que o processo de acumulação é guiado por um ciclo em que cada caractere do texto original é analisado sequencialmente.
def codifica(texto_normal,chave):
    """Codifica um texto pelo método de substituição. A chave é a distância
    para codificar. Exemplo: 'a' passa a 'c' se chave for 2."""
    texto_enc =''
    for car in texto_normal:
        texto_enc = texto_enc + substitui(car,chave)
    return texto_enc
Este programa funciona caso a função substitui fizer o pretendido: substituir um caractere pelo seu substituto de acordo com a chave. Podemos testar o programa desde que façamos uma implementação preliminar desta função auxiliar:
def substitui(car,chave):
 return ‘a’
Se testarmos o resultado será um texto do mesmo comprimento que o original formado apenas pelo caractere a. Nada de muito entusiasmante! No entanto, esta forma de proceder permite testar a lógica da nossa solução. Vamos então implementar a sério a função. A nossa solução usa o facto de cada caractere ter um código numérico. Por exemplo, o a tem como código 97. Existem duas funções em Python que nos vão ajudar: ord(car), fornece o código do car e chr(num) que dá o caractere que tem num como código.
def substitui(car,chave):
    return chr(ord(car)+chave)
E já está! Suponhamos que queremos também obter o original de um texto codificado de acordo com uma dada chave. Trivial:
def descodifica(texto_normal,chave):
    """Descodifica um texto pelo método de substituição. A codificação foi feita de acordo 
    com a seguinte estratégia. A chave é a distância
    para codificar. Exemplo: 'a' passa a 'c' se chave for 2."""
    texto_enc =''
    for car in texto_normal:
        texto_enc = texto_enc + substitui(car,-chave)
    return texto_enc
Como se pode verificar esta função é quase idêntica à sua inversa. A única coisa que mudou é que na chamada da substitui usamos o simétrico (-chave) como valor.

Esta solução é um pouco limitada e supõe que o alfabeto é infinito à esquerda e à direita. Com efeito, se tivermos um caractere que tem o código de valor máximo (ou mínimo) qual vai ser o seu substituto. Por outro lado, existem códigos que não correspondem a letras, mas antes a sinais ou caracteres de controlo. Que fazer? Em baixo apresentamos uma solução para estas questões. Passa por definir explicitamente o alfabeto, e usar o método de procura do índice de um caractere numa cadeia (alfabeto). Por outro lado, para codificar os caracteres nos extremos do alfabeto, usamos a aritmética módulo tamanho do alfabeto (operação %). Na prática, isto corresponde a termos os caracteres organizados de forma circular.
def codifica(texto_normal,chave):
    """Codifica um texto pelo método de substituição. A chave é a distância
    para codificar. Exemplo: 'a' passa a 'c' se chave for 2. Supõe que
    os caracteres são as 26 letras (minúsculas) do alfabeto  e o branco."""
    alfabeto = 'abcdefghijklmnopqrstuvwxyz '
    texto_encriptado = ''
    for car in texto_normal:
        novo_codigo = (alfabeto.index(car) + chave) % len(alfabeto)
        novo_car = alfabeto[novo_codigo]
        texto_encriptado = texto_encriptado + novo_car
    return texto_encriptado
Notar que nesta solução não usamos nenhuma função auxiliar. Mas isso pode ser feito sem problemas, considerando que é a função substitui que sabe qual é o alfabeto. Fica para o leitor a escrita do equivalente para descodificar.

Sem comentários:

Enviar um comentário