"Todo homem é cercado por uma vizinhança de espiões voluntários" (Jane Austen, A abadia de Nothanger)
A cifra reversa criptografa uma mensagem imprimindo-a em ordem reversa. Então, 'Olá, mundo!' criptografa para '!odnum ,álO'. Para descriptografar, ou obter a mensagem original, você simplesmente inverte a mensagem criptografada. As etapas de criptografia e descriptografia são as mesmas.
No entanto, essa cifra reversa é fraca, o que torna fácil descobrir o texto simples. Só de olhar para o texto cifrado, você pode descobrir que a mensagem está em ordem reversa.
.otircse átse euq o rirbocsed áriugesnoc adnia etnemlevavorp êcov ,odafargotpirc ajetse euq omsem ,olpmexe roP
Mas o código para o programa de cifra reversa é fácil de explicar, então o usaremos como nosso primeiro programa de criptografia.
A função len()
Loops while
Dados do tipo booleanos
Operadores de comparação
Condições
Blocos
Vejamos o código para gerar a cifra reversa:
# --- Cifra reversa --- #
mensagem = 'Três podem guardar um segredo, se dois deles estiverem mortos.' # 1
traducao = '' # 2
tamanho_mensagem = len(mensagem) - 1 # 3
while tamanho_mensagem >= 0: # 4
traducao += mensagem[tamanho_mensagem] # 5
tamanho_mensagem -= 1 # 6
print(traducao) # 7
Para decifrar esta mensagem, copie o texto .sotrom merevitse seled siod es ,oderges mu radraug medop sêrT para a área de transferência. Então cole-o como o valor da string armazenado na variável mensagem (1). Certifique-se de manter as aspas simples no começo e no fim da string. A nova linha se parece com isso:
mensagem = '.sotrom merevitse seled siod es ,oderges mu radraug medop sêrT'
Agora, quando você executar a célula, a saída descriptografa a mensagem original.
A primeira linha da célula é um comentário explicando o que é o programa.
Em 1, a linha armazena a string que queremos criptografar em uma variável chamada mensagem:
mensagem = 'Três podem guardar um segredo, se dois deles estiverem mortos.'
Sempre que queremos criptografar ou descriptografar uma nova string, basta digitar a string diretamente no código na variável.
A variável traducao (2) é onde nosso programa armazenará a string invertida:
traducao = ''
No início do programa, a variável traducao contém esta string em branco. (Lembre-se de que a string em branco tem dois caracteres de aspas simples, não um caractere de aspas duplas).
Em 3, há uma instrução de atribuição que armazena um valor em uma variável chamada tamanho_mensagem:
tamanho_mensagem = len(mensagem) - 1 # 3
A expressão avaliada e armazenada na variável é len(mensagem) - 1. A primeira parte desta expressão, len(mensagem), é uma chamada de função para a função len(), que aceita um argumento de string, assim como print(), e retorna um valor inteiro de quantos caracteres estão na string (ou seja, o comprimento da string). Neste caso, passamos a variável mensagem para len(), então len(mensagem) retorna quantos caracteres estão no valor da string armazenado em mensagem.
Vamos experimentar a função len():
print(len('Olá'))
print(len(''))
s = 'Gui'
print(len(s))
print(len('Olá,' + ' ' + 'mundo!'))
Do valor de retorno de len(), sabemos que a string 'Olá' tem três caracteres e a string em branco tem zero caracteres. Se armazenarmos a string 'Gui' em uma variável e então passarmos a variável para len(), a função retornará 3. Se passarmos a expressão 'Olá,' + ' ' + 'mundo!' para a função len(), ela retornará 11. O motivo é que 'Olá,' + ' ' + 'mundo!' avalia para o valor da string 'Olá, mundo!', que tem 11 caracteres. (O espaço e o ponto de exclamação contam como caracteres).
Agora que você entende como a função len() funciona, vamos retornar ao item 3 do programa. Em 3, encontra-se o índice do último caractere em mensagem subtraindo 1 de len(mensagem). É necessário subtrair 1 porque os índices de, por exemplo, uma string de 3 caracteres como 'Olá' são de 0 a 2. Este inteiro é então armazenado na variável tamanho_mensagem.
Em 4, temos um tipo de instrução Python chamada de loop while ou instrução while:
while tamanho_mensagem >= 0: # 4
Uma condição (ou instrução) é uma expressão usada em uma instrução while. O bloco de código na instrução while será executado enquanto a condição for verdadeira.
Para entender os loops while, primeiro você precisa aprender sobre booleanos, operadores de comparação e blocos.
O tipo de dado booleano tem apenas dois valores: True ou False. Esses valores booleanos, ou bools, diferenciam maiúsculas de minúsculas (você sempre precisa colocar o T e o F em maiúsculas, enquanto deixa o restante em minúsculas). Eles não são valores de string, então você não coloca aspas em True ou False.
Experimente alguns bools inserindo o seguinte:
b = True
print(b)
b = False
print(b)
Como um valor de qualquer outro tipo de dado, os bools podem ser armazenados em variáveis.
Em 4, observe a expressão após a palavra-chave while:
while tamanho_mensagem >= 0: # 4
A expressão que segue a palavra-chave while (a parte tamanho_mensagem >= 0) contém dois valores (o valor na variável tamanho_mensagem e o valor inteiro 0) conectados pelo sinal >=, chamado de operador “maior que ou igual”. O operador >= é um operador de comparação.
Usamos operadores de comparação para comparar dois valores e avaliar para um valor booleano True ou False. A Tabela 1 lista os operadores de comparação:
Tabela 1: Operadores lógicos.
Insira as seguintes expressões para ver o valor booleano que elas avaliam:
0 < 6
6 < 0
50 < 10.5
10.5 < 11.3
10 < 10
A expressão 0 < 6 retorna o valor booleano True porque o número 0 é menor que o número 6. Mas como 6 não é menor que 0, a expressão 6 < 0 é avaliada como False. A expressão 50 < 10.5 é False porque 50 não é menor que 10.5. A expressão 10.5 < 11.3 é avaliada como True porque 10.5 é menor que 11.3.
Olhe novamente para 10 < 10. É False porque o número 10 não é menor que o número 10. Eles são exatamente iguais. (Se Maria tivesse a mesma altura que João, você não diria que Maria era mais baixa que João. Essa afirmação seria falsa).
Insira algumas expressões usando os operadores <= (menor ou igual a) e >= (maior ou igual a):
10 <= 20
10 <= 10
10 >= 20
20 >= 20
Observe que 10 <= 10 é True porque o operador verifica se 10 é menor ou igual a 10. Lembre-se de que para os operadores “menor ou igual a” e “maior ou igual a”, o sinal < ou > sempre vem antes do sinal =.
Agora insira algumas expressões que usam os operadores == (igual a) e != (diferente de) para ver como elas funcionam:
10 == 10
10 == 11
10 != 10
10 != 11
Esses operadores funcionam como você esperaria para inteiros. Comparar inteiros que são iguais entre si com o operador == avalia como True e valores desiguais como False. Quando você compara com o operador !=, é o oposto.
As comparações de strings funcionam de forma semelhante:
'Olá' == 'Olá'
'Olá' == 'Tchau'
'Olá' == 'OLÁ'
'Tchau' != 'Olá'
Capitalização importa para Python, então valores de string que não correspondem exatamente à capitalização não são a mesma string. Por exemplo, as strings 'Olá' e 'OLÁ' não são iguais entre si, então compará-las com == avalia como False.
Observe a diferença entre o operador de atribuição (=) e o operador de comparação “igual a” (==). O sinal de igual simples (=) é usado para atribuir um valor a uma variável, e o sinal de igual duplo (==) é usado em expressões para verificar se dois valores são iguais. Se você estiver perguntando ao Python se duas coisas são iguais, use ==. Se você estiver dizendo ao Python para definir uma variável para um valor, use =.
Em Python, valores de string e inteiros são sempre considerados valores diferentes e nunca serão iguais entre si. Por exemplo, insira o seguinte:
10 == 'Olá'
10 == '10'
10 == 10.0
Embora pareçam semelhantes, o inteiro 10 e a string '10' não são considerados iguais porque uma string não é o mesmo que um número. Inteiros e números de ponto flutuante podem ser iguais entre si porque ambos são números.
Ao trabalhar com operadores de comparação, lembre-se de que cada expressão sempre é avaliada como um valor True ou False.
Um bloco é uma ou mais linhas de código agrupadas com a mesma quantidade mínima de recuo (ou seja, o número de espaços na frente da linha).
Um bloco começa quando uma linha é recuada por quatro espaços. Qualquer linha seguinte que também seja recuada por pelo menos quatro espaços é parte do bloco. Quando uma linha é recuada com outros quatro espaços (para um total de oito espaços na frente da linha), um novo bloco começa dentro do primeiro bloco. Um bloco termina quando há uma linha de código com o mesmo recuo de antes do bloco começar.
Vamos dar uma olhada em algum código imaginário (não importa qual seja o código, porque vamos focar apenas no recuo de cada linha). Os espaços recuados são substituídos por pontos aqui para torná-los mais fáceis de contar:
codigo # 0 espaços de recuo
....codigo # 4 espaços de recuo
....codigo # 4 espaços de recuo
........codigo # 8 espaços de recuo
....codigo # 4 espaços de recuo
....codigo # 4 espaços de recuo
codigo # 0 espaços de recuo
Você pode ver que a linha 1 não tem recuo; ou seja, não há espaços na frente da linha de código. Mas a linha 2 tem quatro espaços de recuo. Como essa é uma quantidade maior de recuo do que a linha anterior, sabemos que um novo bloco começou. A linha 3 também tem quatro espaços de recuo, então sabemos que o bloco continua na linha 3.
A linha 4 tem ainda mais recuo (oito espaços), então um novo bloco começou. Este bloco está dentro do outro bloco. Em Python, você pode ter blocos dentro de blocos.
Na linha 5, a quantidade de recuo diminuiu para quatro, então sabemos que o bloco na linha anterior terminou. A linha 4 é a única linha naquele bloco. Como a linha 5 tem a mesma quantidade de recuo que o bloco nas linhas 2 e 3, ela ainda faz parte do bloco externo original, mesmo que não faça parte do bloco na linha 4.
A linha 6 é uma linha em branco, então simplesmente a pulamos; ela não afeta os blocos.
A linha 7 tem quatro espaços de recuo, então sabemos que o bloco que começou na linha 2 continuou até a linha 7.
A linha 8 tem zero espaços de recuo, o que é menos recuo do que a linha anterior. Essa diminuição no recuo nos diz que o bloco anterior, o bloco que começou na linha 2, terminou.
Este código mostra dois blocos. O primeiro bloco vai da linha 2 até a linha 7. O segundo bloco consiste apenas da linha 4 (e está dentro do outro bloco).
Blocos nem sempre precisam ser delimitados por quatro espaços. Blocos podem usar qualquer número de espaços, mas a convenção é usar quatro por recuo.
Vamos dar uma olhada na instrução while completa:
while tamanho_mensagem >= 0:
traducao += mensagem[tamanho_mensagem]
tamanho_mensagem -= 1
print(traducao) # 7
Uma instrução while diz ao Python para primeiro verificar o que a condição avalia, que na linha 8 é tamanho_mensagem >= 0. Você pode pensar no comando while tamanho_mensagem >= 0 como: "Enquanto a variável tamanho_mensagem for maior ou igual a zero, continue executando o código no bloco seguinte." Se a condição for avaliada como True, a execução do programa entra no bloco após a instrução while. Observando o recuo, você pode ver que este bloco é composto por dois comandos. Quando atinge o final do bloco, a execução do programa salta de volta para a instrução while e verifica a condição novamente. Se ainda for True, a execução salta para o início do bloco e executa o código no bloco novamente.
Se a condição da instrução while for avaliada como False, a execução do programa pulará o código dentro do bloco seguinte e saltará para a primeira linha após o bloco (7).
Tenha em mente que em 3, a variável tamanho_mensagem é primeiro definida como o comprimento da mensagem menos 1, e o loop while em 4 continua executando as linhas dentro do bloco seguinte até que a condição while tamanho_mensagem >= 0 seja False:
tamanho_mensagem = len(mensagem) - 1 # 3
while tamanho_mensagem >= 0: # 4
traducao += mensagem[tamanho_mensagem] # 5
tamanho_mensagem -= 1 # 6
print(traducao) # 7
Em 5, temos uma declaração de atribuição que armazena um valor na variável traducao. O valor armazenado é o valor atual de traducao concatenado com o caractere no índice tamanho_mensagem em mensagem. Como resultado, o valor da string armazenado em traducao “cresce” um caractere por vez até se tornar a string totalmente criptografada.
Em 6, também há uma declaração de atribuição. Ela pega o valor inteiro atual em tamanho_mensagem e subtrai 1 dele (isso é chamado de decrementar a variável). Então, ela armazena esse valor como o novo valor de tamanho_mensagem.
Ao final temos 7, mas como essa linha tem menos recuo, o Python sabe que o bloco da instrução while terminou. Então, em vez de passar para 7, a execução do programa salta de volta para 4, onde a condição do loop while é verificada novamente. Se a condição for True, as linhas dentro do bloco são executadas novamente. Isso continua acontecendo até que a condição seja False (ou seja, quando tamanho_mensagem é menor que 0), nesse caso a execução do programa vai para a primeira linha após o bloco (7).
Vamos pensar no comportamento desse loop para entender quantas vezes ele executa o código no bloco. A variável tamanho_mensagem começa com o valor do último índice de mensagem, e a variável traducao começa como uma string em branco. Então, dentro do loop, o valor de mensagem[tamanho_mensagem] (que é o último caractere na string mensagem, porque tamanho_mensagem terá o valor do último índice) é adicionado ao final da string traduzida.
Então o valor em tamanho_mensagem é decrementado (isto é, reduzido) por 1, significando que mensagem[tamanho_mensagem] será o segundo ao último caractere. Então enquanto tamanho_mensagem como um índice continua se movendo do final da string em mensagem para a frente, a string mensagem[tamanho_mensagem] é adicionada ao final de traducao. É assim que traducao acaba segurando o reverso da string em mensagem. Quando tamanho_mensagem é finalmente definido como -1, o que acontece quando alcançamos o índice 0 da mensagem, a condição do loop while é False, e a execução pula para a função print().
No final do programa (7), imprimimos o conteúdo da variável traducao (isto é, a string '.sotrom merevitse seled siod es ,oderges mu radraug medop sêrT') na tela. Isso mostra ao usuário como a string invertida se parece.
Se você ainda estiver tendo problemas para entender como o código no loop while inverte a string, tente adicionar a nova linha ao bloco do loop:
mensagem = 'Três podem guardar um segredo, se dois deles estiverem mortos.'
traducao = ''
tamanho_mensagem = len(mensagem) - 1
while tamanho_mensagem >= 0:
traducao += mensagem[tamanho_mensagem]
print(f'tamanho_mensagem é: {tamanho_mensagem}, mensagem[tamanho_mensagem] é: {mensagem[tamanho_mensagem]}, traducao é: {traducao}') # 1
tamanho_mensagem -= 1
print(traducao)
Em 1, é imporesso os valores de tamanho_mensagem, mensagem[tamanho_mensagem] e traducao junto com rótulos de string cada vez que a execução passa pelo loop (ou seja, em cada iteração do loop). Agora, quando você executa o programa, pode ver como a variável traduzida "cresce".
A linha de saída, 'tamanho_mensagem é: 61, mensagem[tamanho_mensagem] é: ., traducao é: .', mostra o que as expressões tamanho_mensagem, mensagem[tamanho_mensagem] e traducao avaliam depois que a string mensagem[tamanho_mensagem] foi adicionada ao final de traducao, mas antes de tamanho_mensagem ser decrementado. Você pode ver que a primeira vez que a execução do programa passa pelo loop, tamanho_mensagem é definido como 61, então mensagem[tamanho_mensagem] (ou seja, mensagem[61]) é a string '.'. A variável traducao começou como uma string em branco, mas quando mensagem[tamanho_mensagem] foi adicionada ao final dela, ela se tornou o valor da string '.'.
Na próxima iteração do loop, a saída é 'tamanho_mensagem é 60 , mensagem[tamanho_mensagem] é s , traducao é .s'. Você pode ver que tamanho_mensagem foi decrementado de 61 para 60, então agora mensagem[tamanho_mensagem] é mensagem[60], que é a string 's'. Esse 's' é adicionado ao final de traducao, então traducao agora é o valor '.s'.
Agora você pode ver como a string da variável traduzida é lentamente “crescida” de uma string em branco para a mensagem invertida.
Os programas neste estudo são todos projetados para que as strings que estão sendo criptografadas ou descriptografadas sejam digitadas diretamente no código-fonte como instruções de atribuição. Isso é conveniente enquanto estamos desenvolvendo os programas, mas você não deve esperar que os usuários se sintam confortáveis modificando o código-fonte eles mesmos. Para tornar os programas mais fáceis de usar e compartilhar, você pode modificar as instruções de atribuição para que elas chamem a função input(). Você também pode passar uma string para input() para que ele exiba um prompt para o usuário inserir uma string para criptografar. Por exemplo, altere a variável mensagem para isto:
mensagem = input('Digite a mensagem: ')
Quando você executa o programa, ele imprime o prompt na tela e espera que o usuário insira uma mensagem. A mensagem que o usuário insere será o valor da string que é armazenado na variável mensagem. Quando você executa o programa agora, você pode inserir qualquer string que desejar:
mensagem = input('Digite a mensagem: ')
traducao = ''
tamanho_mensagem = len(mensagem) - 1
while tamanho_mensagem >= 0:
traducao += mensagem[tamanho_mensagem]
tamanho_mensagem -= 1
print(traducao)
Exercício 01: O que o seguinte trecho de código imprime na tela:
print(len('Olá') + len('Olá'))
Exercício 01: O que esse código imprime:
i = 0
while i < 3:
print('Olá')
i += 1
Exercício 03: O que esse código imprime:
i = 0
s = 'Olá'
while i < 3:
s += s[i]
i += 1
print(s)
Exercício 04: O que esse código imprime:
i = 0
while i < 4:
while i < 6:
i += 2
print(i)
Acabamos de concluir nosso segundo programa, que manipula uma string em uma nova string usando técnicas do Capítulo 3, como indexação e concatenação. Uma parte fundamental do programa foi a função len(), que pega um argumento de string e retorna um inteiro de quantos caracteres há na string.
Você também aprendeu sobre o tipo de dado booleanos, que tem apenas dois valores, True e False. Os operadores de comparação ==, !=, <, >, <= e >= podem comparar dois valores e avaliar um valor booleano.
Condições são expressões que usam operadores de comparação e avaliam para um tipo de dado booleanos. Elas são usadas em loops while, que executarão código no bloco após a instrução while até que a condição seja avaliada como False. Um bloco é composto de linhas com o mesmo nível de recuo, incluindo quaisquer blocos dentro delas.
Agora que você aprendeu a manipular texto, você pode começar a fazer programas que o usuário pode executar e interagir. Isso é importante porque o texto é a principal forma de o usuário e o computador se comunicarem entre si.