CS50: S2 | Readability e a Complexidade Textual
Tags: braziliandevs
Published: 2022-05-05 13:42:52

## Introdução

Esse exercício visa utilizar o *readability* como medida de complexidade textual. Um exemplo de aplicativo do dia a dia que utiliza um sistema de *readability* para dizer se o seu texto está fácil de ser compreendido ou não, é o [Hemingway Editor](hemingwayapp.com). Eles utilizam algum algoritmo que analisa quantos advérbios, se faz uso ou não da voz passiva e por aí vai.

Nesta atividade será algo bem mais simples, iremos **analisar** a quantidade de letras, palavras e sentenças, assim conseguiremos utilizar o index de Coleman-Liau projetado exatamente para a *lingua inglesa*, para descobrir a complexidade do texto.

`A fórmula utilizada é: index = 0.0588 * L - 0.296 * S - 15.8`

Sem mais delongas, vamos começar o exercicio.

## Quebrando o código

- Headers utilizados
```c
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
```

- Prototipos declarados
```c
int numberOfLetters(string text);
int numberOfWords(string text);
int numberOfSentences(string text);

float indexL(int letters, int words);
float indexS(int sentences, int words);
float colemanLiau(float L, float S);

void showGrade(float index);
```

- função Main
```c
int main(void)
{
    string text = get_string("Text: ");
    int number_of_letters = numberOfLetters(text);
    int number_of_words = numberOfWords(text);
    int number_of_sentences = numberOfSentences(text);

    float L = indexL(number_of_letters, number_of_words);
    float S = indexS(number_of_sentences, number_of_words);

    float indexGrade = colemanLiau(L, S);

    showGrade(indexGrade);
}
```

Gostaria de aproveitar esse ponto para dizer que **não** existe uma só forma de resolver o problema, e provavelmente você pode ter feito algo completamente diferente do que eu fiz, e está tudo bem.

### Contando letras

Na [aula 2](https://dev.to/mpfdev/cs50-passando-pela-semana-2-191i) vimos que as **strings** (textos) são `arrays de caracteres`. E todo essa resolução ela gira em torno desse *conceito* muito **importante**!

```c
int numberOfLetters(string text) {
    int counter = 0;
    for(int i = 0; i < strlen(text); i++) {
        if(text[i] >= 'a' && text[i] <= 'z') {
            counter++;
        } else if(text[i] >= 'A' && text[i] <= 'Z') {
            counter++;
        }
    }

    return counter;
}
``` 

- Temos um contador que inicialmente tem valor 0.

Pois nenhuma letra foi contada até agora, durante a sua inicialização.

- Monta-se a estrutura do loop, mas dessa vez o nosso limitador é `strlen()`.

No [Manual do CS50](manual.cs50.io) temos na biblioteca `string.h` a função **strlen**.
É por isso que incluimos o `string.h` no nosso header. Para que possamos ter acesso a função `strlen()`.
E o que ela faz? Ela retorna o tamanho dessa string(texto).

- Começam as condicionais

Como iremos de letra em letra, utilizando as *bracket notations*. Caso não se lembre, reveja a parte da aula que fala sobre **Arrays**.
E iremos comparar se a letra está entre **a** a **z**, minúscula, ou **A** a **Z**, maiúscula.

- Caso estejam, adicionará um ao nosso contador e pulará para a próxima letra.

- Ao final, retorna o valor desse contador.

```c
int number_of_letters = numberOfLetters(text);
``` 

Com esse valor retornado, eu armazeno esse **valor** dentro de uma **variável** para ser usada mais tarde.

### Contando palavras

O conceito é o mesmo de cima, a diferença agora é que farei uso da **Tabela ASCII** e só irei procurar pelo valor correspondente ao **espaço**.

```c
int numberOfWords(string text) {
    int counter = 1;
    for(int i = 0; i < strlen(text); i++) {
        if( (int) text[i] == 32) {
            counter++;
        }
    }

    return counter;
}
```

- Faço um type casting em relação a letra.

**Type Casting** é um processo em C onde a gente troca a variável que pertence a um tipo de dado para outro.
Neste caso, estou transformando um **tipo de dado** char -> int.

![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)

Então por exemplo:
- Char: A > Int: 65
- Char: 0 > Int: 48
- Char: ! > Int: 33
- Char: [espaço] > Int: 32


- O motivo do contador ser UM

Estou partindo do principio que sempre será escrito uma palavra, então sempre terá a primeira palavra colocada, onde eu não terei um marcador pra ser utilizado como referência (um espaço). Então para isso, já considerei que o contador começará com um.

- Ao final, retorna o valor desse contador.

```c
int number_of_words = numberOfWords(text);
```

### Contando sentenças

```c
int numberOfSentences(string text) {
    int counter = 0;

    for(int i = 0; i < strlen(text); i++) {
        if((int) text[i] == 33 || (int) text[i] == 46 || (int) text[i] == 63) {
            counter++;
        }
    }

    return counter;
}
```

- Aqui, valendo-se da mesma regra das palavras

- Desta vez, os maracadores são: o ponto final, o ponto de exclamação, e a interrogação.

- Ao final, retorna o valor desse contador

```c
int number_of_sentences = numberOfSentences(text);
```

E também, como nos dois primeiros, armazenando esses valores em **variáveis** para serem usados posteriormente.

### Indices e o Index Coleman-Liau

`index = 0.0588 * L - 0.296 * S - 15.8`

As fórmulas utilizadas a seguir, elas seguem o dito pelo enunciado. Agora é aplicar valores.

#### Calculando L

```c
float indexL(int letters, int words) {
    return letters * 100.0 / words;
}
```

E utilizando as variáveis onde **armazenamos** os valores até agora, chamamos essa função assim.

```c
float L = indexL(number_of_letters, number_of_words);
```

E agora, **armazenando** esse resultado em uma nova variável

#### Calculando S

```c
float indexS(int sentences, int words) {
    return sentences * 100.0 / words;
}
```

O processo é exatamente o mesmo.

```c
float S = indexS(number_of_sentences, number_of_words);
```

#### Calculando o index Coleman-Liau

De posse dos valores de L e S, criamos uma nova função:

```c
float colemanLiau(float L, float S) {
    return (0.0588 * L) - (0.296 * S) - 15.8;
}
```

E aqui, vou armazenar o valor desse **float** em uma nova variável.

```c
float indexGrade = colemanLiau(L, S);
```

### Exibindo a nota em Tela

De posse dos valor do index, o problema nos pede:

- Caso o valor seja 1 ou menor, exibir: Before Grade 1
- Caso o valor seja 16 ou maior, exibir: Grade 16+
- Caso o valor esteja entre, ser arredondado para o seu inteiro mais próximo.

```c
void showGrade(float index) {
    if(index < 1) {
        printf("Before Grade 1\n");
    } else if (index > 16) {
        printf("Grade 16+\n");
    } else {
        printf("Grade %i\n", (int) round(index));
    }
}
``` 

E aqui, fiz o uso da função `round()`. Essa função, também pode ser encontrada na [Docs do cs50](manual.cs50.io). Ela pertence a biblioteca `math.h`, e também é por isso que adicionamos ao nosso header.

## Resultados

![image check](https://i.imgur.com/3dbmzQU.png)

E a função com headers, prototipos e a main juntas.

```c
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

int numberOfLetters(string text);
int numberOfWords(string text);
int numberOfSentences(string text);

float indexL(int letters, int words);
float indexS(int sentences, int words);
float colemanLiau(float L, float S);

void showGrade(float index);

int main(void)
{
    string text = get_string("Text: ");
    int number_of_letters = numberOfLetters(text);
    int number_of_words = numberOfWords(text);
    int number_of_sentences = numberOfSentences(text);

    float L = indexL(number_of_letters, number_of_words);
    float S = indexS(number_of_sentences, number_of_words);

    float indexGrade = colemanLiau(L, S);

    showGrade(indexGrade);
}
```

Obrigado por ler até aqui, espero que tenha te ajudado.

Estou cobrindo o CS50, semana a semana, e fazendo a resolução de alguns dos exercicios da semana para ajudar quem está começando.

Me siga aqui no dev.to para acompanhar, ou também me siga no [twitter](https://www.twitter.com/mpfdev) para acompanhar quando estou postando ou comentando sobre códigos que estou aprendendo e desenvolvendo.

Te vejo na próxima!