Cifra da Substituição
Na parte 1 vimos sobre a Cifra de César. Como podemos ver na imagem abaixo.
- Entra-se com uma chave númerica
- Essa chave rotaciona em quantas casas a frente será a próxima letra
- Adiciona a letra correspondente ao texto criptografado
- Exibe o texto
Agora faremos diferente.
Entraremos com uma chave que corresponde a 26 letras, onde a posição de cada letra corresponde as letras do alfabeto romano.
- Key: NQXPOMAFTRHLZGECYJIUWSKDVB
- Alfabeto romano: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Dessa forma:
- O A corresponde ao N
- O F corresponde ao M
- O Z corresponde ao B
E assim por diante.
Daqui em diante, eu recomendo fortemente a leitura do artigo passado, pois a lógica usada é a mesma.
Quebrando o código
1) Código em C
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void doCipher(string text, string key);
int main(int argc, string argv[])
{
if(argc != 2) {
printf("Usage: ./substitution key\n");
return 1;
}
if (strlen(argv[1]) != 26) {
printf("Key must contain 26 characters\n");
return 1;
}
string key = argv[1];
string plaintext = get_string("plaintext: ");
doCipher(plaintext, key);
}
void doCipher(string text, string key) {
char cipher[strlen(text)];
for(int i = 0; i < strlen(text); i++) {
if(isalpha(text[i])) {
if(islower(text[i])) {
int position = text[i] - 97;
cipher[i] = tolower(key[position]);
} else {
int position = text[i] - 65;
cipher[i] = key[position];
}
} else {
cipher[i] = text[i];
}
}
printf("ciphertext: %s\n", cipher);
}
2) Pseudocódigo
- Esperar que o usuário informe a chave com 26 caracteres.
- Pedir ao usuário para introduzir uma mensagem
- Iterar sobre a mensagem original
- Substituindo as letras da mensagem original pela posição correspondente a chave
- Exibir mensagem criptografada
3) O que esperamos ao final?
Isto!
Recebendo a chave do usuário
Na aula 2 vimos sobre Interface da Linha de Comando (CLI) e como o usuário pode passar argumentos ao executar nosso programa via terminal.
Aqui, estamos utilizando do argv[]
que é uma array de caracteres. Então utilizando-se disto, guardaremos em uma variável esse argumento que o usuário vai passar que será a nossa chave (key).
string key = argv[1];
No exercicio de César utilizamos o atoi()
para transformar essa string em uma int, o que aqui não será necessário, pois queremos a string completa.
Porque queremos a string?
A String é uma array de chars. E atráves de uma array podemos manipular por meio da bracket notation para encontrar os elementos de acordo com as suas posições.
Pedindo ao usuário por uma mensagem
Aqui nada de diferente do que foi feito tanto na semana 1, quanto nessa semana 2. Utilizamos da biblioteca fornecida pela CS50.h, para termos acesso a função get_string()
.
string plaintext = get_string("plaintext: ");
Pedimos ao usuário pela mensagem e armazenamos em uma váriavel chamada plaintext.
E só isso.
Temos acesso a nossa chave.
Temos acesso a mensagem original
Hora da magia
1) Criamos uma função que vai receber dois argumentos
void doCipher(string text, string key) {
//TODO
}
Um argumento será a mensagem original, o outro será a chave. Para isto criamos dois parâmetros e estabelecemos os tipos de dados esperados.
2) Criamos uma array do tipo char[] para a nossa mensagem criptografada
void doCipher(string text, string key) {
char cipher[strlen(text)];
//TODO
}
Como toda array tem que ter um tamanho específico para que o programa saiba quanto de espaço na memória será alocado. E nós não temos ideia do tamanho do texto que o usuário irá colocar. Estou usando o strlen()
que nós retorna o comprimento de uma string.
Dessa forma, essa nova array criada, sempre terá o mesmo tamanho da mensagem original.
3) Iterando sobre a mensagem original
void doCipher(string text, string key) {
char cipher[strlen(text)];
for(int i = 0; i < strlen(text); i++) {
//TODO
}
}
Criamos um for()
que é um comando de repetição para iterarmos sobre todo o comprimento da mensagem original. Usamos o ponto inicial como valor 0, pois em computação as Arrays são zero-base, ou seja, o elemento inicial começa em 0, não em 1, como fazemos no nosso dia a dia.
4) Verificando se a caracter na posição i é uma letra do alfabeto
void doCipher(string text, string key) {
char cipher[strlen(text)];
for(int i = 0; i < strlen(text); i++) {
if(isalpha(text[i])) {
//TODO
} else {
cipher[i] = text[i];
}
}
printf("ciphertext: %s\n", cipher);
}
A função isalpha()
faz parte da biblioteca do ctype.h
, você pode encontrar todas essas informações no Docs do CS50. Essa função verificar se o caracter é uma letra do alfabeto.
Caso não seja, eu adiciono nessa posição i correspondente ao nosso cipher o mesmo caracter da mensagem original. Pode ser um ponto, uma vírgula, um espaço, interrogação, números, e etc.
5) Verificando se a letra é minúscula
void doCipher(string text, string key) {
char cipher[strlen(text)];
for(int i = 0; i < strlen(text); i++) {
if(isalpha(text[i])) {
if(islower(text[i])) {
int position = text[i] - 97;
cipher[i] = tolower(key[position]);
} else {
int position = text[i] - 65;
cipher[i] = key[position];
}
} else {
cipher[i] = text[i];
}
}
}
Agora que sabe-se que a letra pertence ao alfabeto, ela só pode ser maiúscula ou minúscula.
Então eu verifico se é minúscula, utilizando a função islower()
, que também pertence a biblioteca ctype.h
.
A partir daqui, precisamos novamente da nossa Tabela de caracteres ASCII.
Sabendo-se que nossa string chave é uma array de caracteres com 26 letras, precisamos encontrar a posição dela. E o nosso alfabeto sempre começa com a letra A, podemos ter a certeza que a letra A é a posição 0 do nosso alfabeto romano.
- alfabetoRomano[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- alfabetoRomano[0] => "A"
- alfabetoRomano[5] => "F"
- alfabetoRomano[25] => "Z"
A partir do momento que eu subtraio de acordo com o valor da tabela ASCII, eu também vou encontrar relação para a chave
- key[26] = "NQXPOMAFTRHLZGECYJIUWSKDVB"
- key[0] => "N"
- key[5] => "M"
- key[25] => "B"
E assim, para cada posição da iteração *i* vai adicionando a letra correspondente na nossa array cipher[].
Eu utilizo a função tolower()
, que converte a letra de maiúscula para minúscula, porque a chave, como no exemplo acima, pode estar toda maiúscula, mas se uma letra é minúscula, eu quero que ela continue minúscula.
6) Imprimindo o texto criptogrado em tela
- Fazemos um printf utilizando um código de formato string para um char
void doCipher(string text, string key) {
char cipher[strlen(text)];
for(int i = 0; i < strlen(text); i++) {
if(isalpha(text[i])) {
if(islower(text[i])) {
int position = text[i] - 97;
cipher[i] = tolower(key[position]);
} else {
int position = text[i] - 65;
cipher[i] = key[position];
}
} else {
cipher[i] = text[i];
}
}
printf("ciphertext: %s\n", cipher);
}
- Resultado Final!
Conclusão
Parabéns!
Você conseguiu resolver todos os problemas da semana 2.
Na próxima semana, retornamos com a semana 3, temos muito mais a aprender nos próximos problemas.
Me siga no meu twitter para acompanhar quando estou postando de novo, e sobre o que eu estou estudando.
Até a próxima!
Top comments (0)