Você está na página 1de 9

UNIVERSIDADE FEDERAL DE SERGIPE

DEPARTAMENTO DE MATEMÁTICA

Trabalho da disciplina tópicos de matemática aplicada .

Corretor ortográfico.

Docente: Gastão Florêncio Miranda Júnior.


Discente: Vitória Teles da Silva.

Trabalho da primeira unidade da disciplina de tópicos de


matemática aplicada

São Cristóvão - SE
2023

1
1 Funções auxiliares do programa

O código começa importando as bibliotecas stdio.h, string.h, math.h e stdlib.h.


Stdio.h é a biblioteca padrão de entrada e saída em C, utilizada para operações
de leitura e escrita. String.h é a biblioteca padrão de manipulação de strings em
C, que contém funções para cópia, concatenação, comparação e outras opera-
ções em strings. Math.h é a biblioteca padrão de funções matemáticas em C,
que contém funções como sqrt() para calcular a raiz quadrada de um número e
pow() para calcular a potência de um número. Já stdlib.h é a biblioteca usada
para alocação com a função Malloc.

Em seguida, há uma função convertechi(), essa função converte cada carac-


tere de palavra[ ] em um número da tabela ASCII subtraindo 64, de forma que
o caractere ’A’ seja convertido em 1, ’B’ em 2, e assim por diante, fazendo com
que fique em ordem alfabética.

A seguir, há uma função min() que recebe dois inteiros a e b como parâme-
tros e retorna o menor deles.

Em seguida, vamos definir as funções de distância que foram solicitadas no


item 1 do trabalho, então há uma função dist1() que recebe duas strings i[ ] e
pdig[ ] e dois inteiros m e n como parâmetros, sendo i em relação as palavras
dadas no arquivo e pdig a palavra que será pedida para o usuário digitar. Essa
função calcula a distância de Levenshtein entre as strings i[ ] e pdig[ ]. A distância
de Levenshtein é o número mínimo de operações necessárias para transformar
uma string em outra, sendo que as operações permitidas são: inserir um ca-
ractere, remover um caractere ou substituir um caractere por outro. A função é
recursiva e utiliza a função min( ) para calcular o menor valor entre três possibi-
lidades: 1) remover o último caractere de i[ ] e chamar a função novamente; 2)
remover o último caractere de pdig[ ] e chamar a função novamente; 3) substituir
o último caractere de i[ ] pelo último caractere de pdig[ ] (se eles forem diferentes)
e chamar a função novamente.

A função dist2( ) recebe as mesmas informações que dist1( ), mas calcula a


distância euclidiana entre as strings i[ ] e pdig[ ]. Para isso, a função converte
cada caractere das strings em um número utilizando a função convertechi(), ar-
mazena esses números em arrays num_i[] e num_pdig[] e então utiliza um loop
para percorrer os arrays, calcular a diferença ao quadrado entre os números em
cada posição e somá-las. O resultado é a raiz quadrada dessa soma.

A função dist_ang é a implementação da medida de distância angular entre


duas palavras, calculando o ângulo entre os vetores de representações numé-
ricas de cada letra da palavra. Essa implementação é feita usando a função
convertechi para converter as letras em números e calculando o produto escalar
⟨a,b⟩
e os módulos dos vetores. Para tal, foi usada a função: d(a, b) = 1 − ∥a∥∥b∥ .

A função comparaDistancias é usada pela função qsort para ordenar as pala-


vras de acordo com as distâncias calculadas. Essa função recebe dois ponteiros

2
void a e b, que são convertidos em ponteiros do tipo PalavraDistancia. Essa
estrutura de dados armazena a palavra e a distância calculada em relação à
palavra digitada pelo usuário. A função compara as distâncias e retorna -1 se
a primeira distância for menor do que a segunda, 1 se a primeira distância for
maior do que a segunda e 0 se as distâncias forem iguais.

2 Main

O programa lê um arquivo de texto chamado "Lista-de-Palavras.txt"que contém


uma lista de palavras e, em seguida, solicita ao usuário uma palavra em letras
maiúsculas a ser corrigida.

O programa, então, itera sobre todas as palavras da lista, calculando a dis-


tância da palavra digitada pelo usuário para cada palavra da lista utilizando as
três métricas mencionadas. Essas distâncias são armazenadas em três vetores
de distância: distancias1, distancias2 e distancias3.

O programa utiliza a função qsort( ) para ordenar as palavras da lista de


acordo com as distâncias calculadas, criando uma estrutura de dados Pala-
vraDistancia que contém a palavra e sua respectiva distância para a palavra
digitada. O resultado é armazenado em três arquivos de texto: "resultado-
LEV.txt"para a Distância de Levenshtein, "resultadoEUCLID.txt"para a Distância
Euclidiana e "resultadoANG.txt"para a Distância Angular.

Finalmente, o programa imprime as cinco palavras mais próximas à palavra


digitada para cada uma das métricas utilizadas e escreve as palavras e distâncias
correspondentes nos arquivos de texto criados anteriormente. Essa estratégia foi
utilizada como meio para fazer sugestões de correção para o corretor ortográfico
que foi solicitado para o presente trabalho.
Algumas variáveis utilizadas no programa são:

1. pdig: vetor de caracteres para armazenar a palavra digitada pelo usuário.

2. linha: vetor de caracteres para percorrer as linhas do arquivo de palavras.

3. p1: vetor de ponteiros para armazenar as palavras lidas do arquivo.

4. distancias1, distancias2, distancias3: vetores de distância para armazenar


as distâncias calculadas para cada palavra.

5. PalavraDistancia: estrutura de dados que contém a palavra e sua respec-


tiva distância.

6. arquivo, saida, saida2, saida3: ponteiros de arquivo para abrir e fechar os


arquivos de entrada e saída.

Demais anotações e informações estão comentadas no código apresentado no


próximo tópico.

3
3 O Código

1 # include < stdio .h >


2 # include < string .h >
3 # include < math .h > // virou necessidade em dist2
4 # include < stdlib .h >
5

6 // funcao que converte caractere em numero da tabela ascii


7 void convertechi ( char palavra [] , int numeros [] , int tamanho ) {
8 for ( int e = 0; e < tamanho ; e ++) {
9 numeros [ e ] = ( int ) palavra [ e ] - 64; // TIRA 64 PARA COMECAR A
CONTAR O ALFABERTO DE A = 1 , J QUE A EM ASCII COMECA NO
NUMERO 65.
10 }
11 }
12

13 // funcao de minimo usada em levenshtein


14 int min ( int a , int b ) {
15 if ( a <= b ) {
16 return a ;
17 }
18 else
19 return b ;
20 }
21

22 // levenshtein
23 int dist1 ( char i [] , int m , char pdig [] , int n ) {
24 // caso vazio
25 if ( m == 0) {
26 return n ;
27 }
28 if ( n == 0) {
29 return m ;
30 }
31 int cost ;
32 // se os ultimos caracteres das strings corresponderem
33 if ( i [ m - 1] == pdig [ n - 1]) {
34 cost = 0;
35 }
36 else {
37 cost = 1;
38 }
39 return min (
40 min ( dist1 (i , m - 1 , pdig , n ) + 1 , dist1 (i , m , pdig , n - 1) +
1) ,
41 dist1 (i , m - 1 , pdig , n - 1) + cost
42 );
43 }
44

45 // funcao que calcula a distancia euclidiana entre duas strings


46 double dist2 ( char i [] , int m , char pdig [] , int n ) {

4
47 int maxt = fmax (m , n ) ;
48 int * num_i = ( int *) malloc (( m +1) * sizeof ( int ) ) ;
49 int * num_pdig = ( int *) malloc (( n +1) * sizeof ( int ) ) ;
50 int som = 0;
51 convertechi (i , num_i , m ) ;
52 convertechi ( pdig , num_pdig , n ) ;
53 for ( int e = 0; e < maxt ; e ++) {
54 int val_i , val_pdig ;
55 if ( e < m ) {
56 val_i = num_i [ e ];
57 } else {
58 val_i = 0;
59 }
60 if ( e < n ) {
61 val_pdig = num_pdig [ e ];
62 } else {
63 val_pdig = 0;
64 }
65 som += pow ( val_i - val_pdig , 2) ; // eleva ao quadrado e o for
faz com que vire uma soma
66 }
67 return sqrt ( som ) ;
68 }
69 // Calcula a d i s t n c i a angular entre dois vetores
70 double dist_ang ( char i [] , int m , char pdig [] , int n ) {
71 int maxt = fmax (m , n ) ;
72 int * num_i = ( int *) malloc ( m * sizeof ( int ) ) ;
73 int * num_pdig = ( int *) malloc ( n * sizeof ( int ) ) ;
74 double dot_prod = 0.0 , mod_i = 0.0 , mod_pdig = 0.0;
75 convertechi (i , num_i , m ) ;
76 convertechi ( pdig , num_pdig , n ) ;
77

78 for ( int e = 0; e < maxt ; e ++) {


79 int val_i , val_pdig ;
80 if ( e < m -1) {
81 val_i = num_i [ e ];
82 } else {
83 val_i = 0;
84 }
85 if ( e < n -1) {
86 val_pdig = num_pdig [ e ];
87 } else {
88 val_pdig = 0;
89 }
90 dot_prod += val_i * val_pdig ;
91 mod_i += pow ( val_i , 2) ;
92 mod_pdig += pow ( val_pdig , 2) ;
93 }
94

95 double p1 = dot_prod /( sqrt ( mod_i ) * sqrt ( mod_pdig ) ) ;


96 return (1 - p1 ) ;

5
97 }
98

99 // ////// /////////// ////// f u n o auxiliar do qsort


100 // Definir uma estrutura para armazenar as palavras e suas
dist ncias
101 typedef struct {
102 char * palavra ;
103 float distancia ;
104 } PalavraDistancia ;
105

106 // Definir uma f u n o de c o m p a r a o para qsort


107 int comparaDistancias ( const void *a , const void * b ) {
108 PalavraDistancia * p1 = ( PalavraDistancia *) a ;
109 PalavraDistancia * p2 = ( PalavraDistancia *) b ;
110

111 if ( p1 - > distancia < p2 - > distancia ) {


112 return -1;
113 } else if ( p1 - > distancia > p2 - > distancia ) {
114 return 1;
115 } else {
116 return 0;
117 }
118

119 }
120

121 int main ( void ) {


122 char pdig [30]; // armazenar a palavra digitada
123 char linha [30]; // usado para percorrer as linhas do arquivo
124 char i [30]; // transformar a linha em um vetor de caractere
125 char * p1 [30000];
126 double distancias1 [30000];
127 double distancias2 [30000];
128 double distancias3 [30000];
129 printf ( " Digite uma palavra com todas as letras em m a i s c u l o \
n " ) ; // pede para o u s u r i o a palavra
130 fgets ( pdig ,30 , stdin ) ; // l a palavra
131 size_t n = strlen ( pdig ) ; // conta o tamanho da palavra
digitada
132 FILE * arquivo = fopen ( " Lista - de - Palavras . txt " , " r " ) ;
133 // l o arquivo
134 FILE * saida = fopen ( " resultadoLEV . txt " , " w " ) ;
135 FILE * saida2 = fopen ( " resultadoEUCLID . txt " , " w " ) ;
136 FILE * saida3 = fopen ( " resultadoANG . txt " , " w " ) ;
137 int idx = 0;
138

139 // LINHA DE BAIXO l todas as linhas do arquivo


140 while ( fgets ( linha , 30000 , arquivo ) != NULL && idx < 30000) {
141 size_t m = strlen ( linha ) ; // tamanho da palavra da lista menos
o e s p a o vazio
142 while ( m > 0 && linha [ m - 1] == ’ ’) {
143 m - -;

6
144 } // resolveu o problema de tirar o vazio do fim das palavras
lendo da direita para a esquerda
145 p1 [ idx ] = malloc ( m + 1) ; // aloca m e m r i a para a palavra
146 strncpy ( p1 [ idx ] , linha , m ) ; // copia a palavra lida para a
m e m r i a alocada
147 int levenshtein = dist1 ( p1 [ idx ] , m , pdig , n ) ;
148 double euclidiana = dist2 ( p1 [ idx ] , m , pdig , n ) ;
149 double angular = dist_ang ( p1 [ idx ] , m , pdig , n ) ;
150 distancias1 [ idx ] = levenshtein ;
151 distancias2 [ idx ] = euclidiana ;
152 distancias3 [ idx ] = angular ;
153 idx ++;
154 }
155 fclose ( arquivo ) ;
156 PalavraDistancia pd1 [ idx ];
157 for ( int i = 0; i < idx ; i ++) {
158 pd1 [ i ]. palavra = p1 [ i ];
159 pd1 [ i ]. distancia = distancias1 [ i ];
160 }
161

162 // OrdenarPARALEV
163 qsort ( pd1 , idx , sizeof ( PalavraDistancia ) , comparaDistancias ) ;
164

165 // Imprimir a s a d a ordenada


166 printf ( " \ n D i s t n c i a s depois da o r d e n a o com a d i s t n c i a
de levenshtein :\ n " ) ;
167 for ( int i = 0; i < 5; i ++) {
168 printf ( " %f , % s \ n " , pd1 [ i ]. distancia , pd1 [ i ]. palavra ) ;
169 fprintf ( saida , " Palavra : % s - D i s t n c i a de levenshtein : % f \ n "
, pd1 [ i ]. palavra , pd1 [ i ]. distancia ) ;
170 free ( pd1 [ i ]. palavra ) ;
171 }
172 // / // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / ARRUMANDO O CORRETOR PARA
EUCLIDIANA
173 // calcula as d i s t n c i a s
174 PalavraDistancia pd2 [ idx ];
175 for ( int i = 0; i < idx ; i ++) {
176 pd2 [ i ]. palavra = p1 [ i ];
177 pd2 [ i ]. distancia = distancias2 [ i ];
178 }
179 qsort ( pd2 , idx , sizeof ( PalavraDistancia ) , comparaDistancias )
;
180

181 // Imprimir a s a d a ordenada


182 printf ( " \ n D i s t n c i a s depois da o r d e n a o usando
d i s t n c i a euclidiana :\ n " ) ;
183 for ( int i = 0; i < 5; i ++) {
184 printf ( " %f , % s \ n " , pd2 [ i ]. distancia , pd2 [ i ]. palavra ) ;
185 fprintf ( saida2 , " Palavra : % s - D i s t n c i a Euclidiana : % f \ n
" , pd2 [ i ]. palavra , pd2 [ i ]. distancia ) ;
186

7
187 }
188

189 // // / // / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / Arrumando o corretor


para angular
190 PalavraDistancia pd3 [ idx ];
191 for ( int i = 0; i < idx ; i ++) {
192 pd3 [ i ]. palavra = p1 [ i ];
193 pd3 [ i ]. distancia = distancias3 [ i ];
194 }
195 qsort ( pd3 , idx , sizeof ( PalavraDistancia ) , comparaDistancias ) ;
196

197 // Imprimir a s a d a ordenada


198 printf ( " \ n D i s t n c i a s depois da o r d e n a o usando d i s t n c i a
angular :\ n " ) ;
199 for ( int i = 0; i < 5; i ++) {
200 printf ( " %f , % s \ n " , pd3 [ i ]. distancia , pd3 [ i ]. palavra ) ;
201 fprintf ( saida3 , " Palavra : % s - D i s t n c i a Angular : % f \ n " , pd3 [
i ]. palavra , pd3 [ i ]. distancia ) ;
202 }
203

204 return 0;
205 }

4 Resultados

Foi escolhida a palavra "ZURAR"que seria uma opção de erro ortográfico ao


digitar "ZURRAR"presente no arquivo de leitura fornecido e o resultado obtido é
que a distância de Levenshtein foi a que melhor se aproximou de melhores re-
sultados.

Palavras Levenshtein
Sugestão Distâncias
CURAR 1.000000
DURAR 1.000000
ZURAR
FURAR 1.000000
JURAR 1.000000
MURAR 1.000000

Palavras Euclidiana
Sugestão Distâncias
URRAR 5.830952
TURCO 7.000000
ZURAR
URUBU 7.280110
TROAR 7.348469
VOTAR 7.483315

8
Palavras Angular
Sugestão Distâncias
ROMAN 0.000926
ROMANA 0.001471
ZURAR
TONAL 0.001625
TOMBO 0.002310
TROCO 0.003043

5 Considerações finais

Existem problemas no código, tanto para melhorar o tempo de processamento


quanto para consertar alguns erros lógicos. Por causa disso, não exibi as 10
palavras solicitadas para o presente trabalho.

Você também pode gostar