maketrans – Tabela de tradução de Strings

Já ouviu falar do alfabeto Leet (ou l337)? É um alfabeto empregado principalmente na internet e usado para comunicação entre pessoas, onde algumas letras do alfabeto latino são substituídas por símbolos graficamente parecidos. Utilizando alfabeto leet, a palavra STREET ficaria 57r337, por exemplo. Ou seja, o número 5 substitui a letra S, o número 7 substitui a letra T, 3 substitui a letra E.

Vamos criar uma ferramenta que traduza texto escrito usando o alfabeto tradicional para texto usando alfabeto leet. Uma forma tosca de fazermos isso é substituir todas as ocorrências de determinada letra do alfabeto tradicional por seu correspondente leet. Exemplo:

s = raw_input('Digite uma frase:')
s = s.replace('a', '4')
s = s.replace('t', '7')
s = s.replace('e', '3')
s = s.replace('s', '5')
...
print s

Porém, existe outra forma mais simples e mais elegante, usando uma Tabela de Tradução. Considere a tabela abaixo. Nela temos duas colunas, uma chamada de Entrada e outra chamada de Saída. Usando a tabela de tradução, cada letra da coluna Entrada encontrada no texto será substituída pela sua correspondente na coluna Saída.

Entrada Saída
A 4
B 8
T 7
E 3
S 5
I 1
O 0
Z 2

No módulo string, fornecido juntamente com a biblioteca padrão do Python, temos um método chamado maketrans, que, dadas duas entradas, cria uma tabela de tradução. Por exemplo, para criar a tabela de tradução apresentada acima, utilizamos o código abaixo:

from string import maketrans
entrada = 'ABTESIOZ'
saida   = '48735102'
tabela = maketrans(entrada, saida)
s = raw_input('Digite uma frase para ser convertida para leet:')
print s.translate(tabela)

As variáveis entrada e saida são strings que irão representar as colunas da tabela de tradução. Para cada ocorrência de um caractere da string entrada em uma string que será traduzida, tal caractere será substituído pelo elemento correspondente na variável saida. Por exemplo, todo caractere ‘A’ em uma string a ser traduzida será substituído pelo caractere ‘4’, e assim por diante.

Usando a mesma idéia, podemos escrever um programinha que cifre uma mensagem usando a Cifra de Caesar. Nesse tipo de cifra, cada letra de uma frase é substituída por outra letra, de acordo com um deslocamento do alfabeto tradicional. Considere como exemplo os dois alfabetos abaixo:

a b c d e f g h i j k l m n o p q r s t u v w x y z
c d e f g h i j k l m n o p q r s t u v w x y z a b

O alfabeto da segunda linha possui um deslocamento de 2 em seus caracteres. Agora, podemos cifrar textos de acordo com tais alfabetos. Por exemplo:

hello world  ---->  jgnnq yqtnf

Cada caractere da string original é substituído pelo correspondente da tabela de tradução. ‘h’ é substituído por ‘j’, e assim por diante. Quem vê a mensagem  jgnnq yqtnf  não consegue descobrir qual o significado desta, a não ser que conheça ou descubra o algoritmo utilizado para cifrá-la. É claro que, nesse caso, é muito simples descobrir. Outro exemplo de cifragem usando os mesmos dois alfabetos:

estou saindo ---->  guvqw uckpfq

Como implementar uma Cifra de Caesar simples, com deslocamento 2, em Python?

from string import maketrans

entrada = 'abcdefghijklmnopqrstuvwxyz'
saida   = 'cdefghijklmnopqrstuvwxyzbc'

def cifra_de_caesar(texto):
    tabela = maketrans(entrada, saida)
    return texto.translate(tabela)

print cifra('hello world')

Como vimos nos exemplos anteriores, o método maketrans, combinado com o translate, nos facilita muito a vida na hora de fazer a cifragem/decifragem de uma mensagem. Poderíamos fazer o mesmo com o método replace da string, mas o código ficaria muito maior e difícil de manter.

Maiores informações sobre maketrans: http://docs.python.org/library/string.html#string-functions

Fatiamento (slicing) de Strings em Python

Antes de falarmos de slicing, vamos ver rapidamente o que são as strings em Python. Strings em Python são objetos como outros quaisquer. Podem ser construídos com uma atribuição simples:

>>> s = "hello, world!"

Tendo feito isso, o objeto s possui disponíveis vários métodos:

>>> print s.upper()
HELLO, WORLD!
>>> print s.split(",")
['hello', ' world!']
>>> print s.split(",")[0]
'hello'
>>> print s.replace("world", "dude")
hello, dude!

Acima, são mostrados apenas alguns dos métodos disponíveis para as strings, nativamente em Python. Assim como em outras linguagens, elementos individuais de uma string podem ser acessados via índice:

>>> print s[0]
h
>>> print s[2]
l
>>> print s[12]
!

Para acessar o último elemento de uma string, podemos proceder de duas formas:

>>> print s[len(s)]
!
>>> print s[-1]
!

Uma operação muito interessante que Python fornece para manipulação de strings é o fatiamento (slicing). Fatiamento significa extrair apenas uma parte da string, ou seja, uma substring. Com essa operação, podemos delimitar os limites inferior e superior do pedaço da string que queremos acessar. Por exemplo, se quisermos acessar a substring da posição 0 até a posição 4 na string s original, podemos fazer o seguinte:

>>> print s[0:5]
'hello'
>>> print s[:5]
'hello'
>>> print s[2:4]
ll
>>> print s[7:13]
'world!'
>>> print s[7:]
'world!'
>>> print s[:]
'hello, world!'

Repare que o elemento que reside na posição do limite superior não é retornado juntamente com a string. Veja a primeira linha do código acima, s[0:5] retorna os elementos que residem entre as posições 0 e 5, incluindo a primeira e excluindo a segunda. Como mostrado acima, também podemos omitir um dos limites, ou ambos, quando queremos algo do início até posição x, ou da posição x até o fim.

OK, mas pra que serve isso? Vamos a um exemplo bem simples: extrair o protocolo de uma URL (formato: protocolo://servidor:porta/caminho/para/recurso).

url = "http://localhost:8000/arquivo.iso"
protocolo = url[0:url.index(':')]

Esse é apenas um simples exemplo do poder que essa operação tem. Cabe ressaltar aqui, que o fatiamento cria uma nova string contendo o conteúdo solicitado na operação. Ou seja, a cada operação de fatiamento, uma nova string é criada.

É isso. Faça bom proveito desse recurso que torna o código muito mais limpo e de fácil entendimento.