CS50 : S2 | Cifra da Substituição - Parte 2
Tags: braziliandevs
Published: 2022-05-09 12:26:37

## Cifra da Substituição

Na [parte 1](https://dev.to/mpfdev/cs50-s2-cesar-e-a-substituicao-parte-1-3l37) 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](https://i.imgur.com/sDuhD0u.png)

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](https://dev.to/mpfdev/cs50-s2-cesar-e-a-substituicao-parte-1-3l37), pois a lógica usada é a **mesma**.

## Quebrando o código

1) Código em C

```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!

![final_image_with_results](https://i.imgur.com/OpvAcRe.png)

### Recebendo a chave do usuário

Na [aula 2](https://dev.to/mpfdev/cs50-passando-pela-semana-2-191i) 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).

```c
string key = argv[1];
``` 

No exercicio de [César](https://dev.to/mpfdev/cs50-s2-cesar-e-a-substituicao-parte-1-3l37) 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()`.

```c
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

![magic](https://cdn.pixabay.com/photo/2019/05/14/21/50/storytelling-4203628_960_720.jpg)

### Hora da magia

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

```c
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

```c
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

```c
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

```c
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](manual.cs50.io). 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

```c
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**.

![ASCII Chart](https://s2.glbimg.com/RPbabV4SBKRMLI0glhOnIRbK6GM=/0x0:695x415/984x0/smart/filters:strip_icc()/i.s3.glbimg.com/v1/AUTH_08fbf48bc0524877943fe86e43087e7a/internal_photos/bs/2021/J/r/3dDbw9SueCiU9I8We1tA/2015-02-12-imagem28.jpg)

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

```c
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!
![final_image_with_results](https://i.imgur.com/OpvAcRe.png)

## 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](https://www.twitter.com/mpfdev) para acompanhar quando estou postando de novo, e sobre o que eu estou estudando.

Até a próxima!

![journey](https://cdn.pixabay.com/photo/2022/04/01/22/55/submarine-7105870_960_720.png)