DEV Community

Matheus 🇧🇷
Matheus 🇧🇷

Posted on

CS50 : S2 | Cifra da Substituição - Parte 2

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

final image

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);
}
Enter fullscreen mode Exit fullscreen mode

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!

final_image_with_results

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];
Enter fullscreen mode Exit fullscreen mode

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: ");
Enter fullscreen mode Exit fullscreen mode

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

magic

Hora da magia

1) Criamos uma função que vai receber dois argumentos

void doCipher(string text, string key) {
    //TODO
}
Enter fullscreen mode Exit fullscreen mode

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
}
Enter fullscreen mode Exit fullscreen mode

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
    }

}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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];
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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.

ASCII Chart

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);
}
Enter fullscreen mode Exit fullscreen mode
  • Resultado Final! final_image_with_results

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!

journey

Top comments (0)