Skip to content

Instantly share code, notes, and snippets.

@jj-marinho
Created July 15, 2020 23:34
Show Gist options
  • Save jj-marinho/be9fc30da78fb2bcd078a85a0332ccb8 to your computer and use it in GitHub Desktop.
Save jj-marinho/be9fc30da78fb2bcd078a85a0332ccb8 to your computer and use it in GitHub Desktop.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <regex.h>
#define BUFFER 512
typedef struct Patterns {
char *regexFreq; // Regex usado na conta de frequencia
char *regexLongest; // Regex usado para achar a palavra mais longa
char *regexAll; // Regex usado na impressão de todos os matchs
char *closestWord; // Achar a palavra mais próxima desta no arquivo;
} Patterns;
// Funções usadas no projeto
// Documentação no "cabeçalho" de cada uma
int parseFile(char ***dictionary);
Patterns getPatterns(void);
void printWordFacts(char **dict, int dictSize);
void printPalindromeAmount(char ** dict, int dictSize);
void printFreqRegex(char *regex, char **dict, int dictSize);
void printLongestWordRegex(char *regex, char **dict, int dictSize);
void printAllMatchingWords(char *pattern, char **dict, int dictSize);
void printClosestWord(char *word, char **dict, int dictSize);
int compare(const void* a, const void* b);
int main(void) {
// Procedimento completo de abertura do arquivo
char **dictionary;
int dictSize = parseFile(&dictionary);
// Pegando os regexes e palavras de comparação
Patterns patterns = getPatterns();
// Todas as funções de print modularizadas
// Fatos inicias
printWordFacts(dictionary, dictSize);
// Frequencias
printFreqRegex(patterns.regexFreq, dictionary, dictSize);
free(patterns.regexFreq);
// Palindromos
printPalindromeAmount(dictionary, dictSize);
// Palavra mais longa
printLongestWordRegex(patterns.regexLongest, dictionary, dictSize);
free(patterns.regexLongest);
// Todas as palavras relacionadas
printAllMatchingWords(patterns.regexAll, dictionary, dictSize);
free(patterns.regexAll);
// Palavra mais semelhante
printClosestWord(patterns.closestWord, dictionary, dictSize);
free(patterns.closestWord);
// Finalizando o programa
for (int j = 0; j < dictSize; j++) {
free(dictionary[j]);
}
free(dictionary);
return 0;
}
// Atravessa o arquivo, armazenando todas as palavras incluidas
// em uma matriz "dictionary". Retorna o tamanho da matriz
int parseFile(char ***dictionary) {
// Pegando o nome do arquivo e abrindo-o
char *fileName = malloc(32);
scanf("%[^\n]", fileName);
FILE * filePointer = fopen(fileName, "r");
free(fileName);
int i = -1;
*dictionary = malloc(sizeof(char *));
do {
// Realloc caso o buffer seja esgotado
if (++i % BUFFER == 0) {
*dictionary = realloc(*dictionary, sizeof(char *) * BUFFER * (1 + i / BUFFER));
}
(*dictionary)[i] = calloc(32, 1);
// Pegando a palavra do arquivo e armazendo no dictionary,
// Depois disso eliminando o \n com o fgetc()
fscanf(filePointer, "%[^\n]", (*dictionary)[i]);
fgetc(filePointer);
} while (!feof(filePointer));
free((*dictionary)[i]);
*dictionary = realloc(*dictionary, sizeof(char * ) * i);
fclose(filePointer);
return i;
}
// Pega os 4 padrões descritos na struct Patterns
// através do stdin.
// Retorna a struct contendo os padrões
Patterns getPatterns(void) {
Patterns patterns;
patterns.regexFreq = calloc(16, 1);
patterns.regexLongest = calloc(16, 1);
patterns.regexAll = calloc(16, 1);
patterns.closestWord = calloc(16, 1);
scanf("%s\n%s\n%s\n%s",
patterns.regexFreq,
patterns.regexLongest,
patterns.regexAll,
patterns.closestWord
);
return patterns;
}
// Imprime, em sequência:
// Número total de palavras, palavra mais curta, palavra mais longa
void printWordFacts(char **dict, int dictSize) {
// Posições da palavra mais longa e curta no dict
int longestIndex = 0, shortestIndex = 0;
// Tamanho de cada palavra, para evitar a necessidade de recalcular dentro da função
int longestLen = strlen(dict[0]),
shortestLen = longestLen,
currentLen = 0;
// Dentro de um loop, procura pela maior e menor palavra do dicionário
for (int i = 0; i < dictSize; i++) {
currentLen = strlen(dict[i]);
if (currentLen > longestLen) {
longestLen = currentLen;
longestIndex = i;
} else if (currentLen < shortestLen && currentLen != 0) {
shortestLen = currentLen;
shortestIndex = i;
}
}
printf("%d\n%s\n%s\n", dictSize, dict[shortestIndex], dict[longestIndex]);
}
// Checa a quantidade de palíndromos
void printPalindromeAmount(char ** dict, int dictSize) {
int numPalindromes = 0,
wordSize = 0,
isPalindrome = 1;
// Checa se a última letra e a primeira são iguais
// Faz isso para todas as letras.
// Se todas forem iguais, isPalindrome continua como 1
// Ao somar, se isPalindrome for 1, aumenta o total de palindromos
for (int i = 0; i < dictSize; i++) {
wordSize = strlen(dict[i]) - 1;
isPalindrome = 1;
for (int j = 0; j < (wordSize - j) && isPalindrome; j++) {
if (dict[i][j] != dict[i][wordSize - j]) isPalindrome = 0;
}
numPalindromes += isPalindrome;
}
printf("%d\n", numPalindromes);
}
// Função que acha a frequência de matches do P1 em relação ao dicionário
void printFreqRegex(char *pattern, char **dict, int dictSize) {
int totalMatches = 0, result;
regex_t regex;
regcomp(&regex, pattern, REG_EXTENDED);
// Se houver match no regex, aumenta o número total de matches em 1
for(int i = 0; i < dictSize; i++) {
result = regexec(&regex, dict[i], 0, NULL, 0);
if (result == 0) totalMatches++;
}
regfree(&regex);
printf("%d\n", totalMatches);
}
// Calcula qual a maior palavra do dicionário que obedece o pattern
// através de regex
void printLongestWordRegex(char *pattern, char **dict, int dictSize) {
int length = 0, index = 0, result;
regex_t regex;
regcomp(&regex, pattern, REG_EXTENDED);
// Se houver match, checa qual a maior palavra
for(int i = 0; i < dictSize; i++) {
result = regexec(&regex, dict[i], 0, NULL, 0);
if (result == 0) {
if (length < strlen(dict[i])) {
index = i;
length = strlen(dict[i]);
}
}
}
regfree(&regex);
printf("%s\n", dict[index]);
}
// Imprime todas as palavras no DICT que apresentam o padrão PATTERN
void printAllMatchingWords(char *pattern, char **dict, int dictSize) {
regex_t regex;
regcomp(&regex, pattern, REG_EXTENDED);
qsort(dict, dictSize, sizeof(char *), compare);
int result;
// Se houver match do regex, imprime o resultado
// Como já houve ordenação anteriormente, os resultados sairão ordenados
for(int i = 0; i < dictSize; i++) {
result = regexec(&regex, dict[i], 0, NULL, 0);
if (result == 0) {
printf("%s\n", dict[i]);
}
}
regfree(&regex);
}
// Usa um sistema de pontuação para determinar qual a palavra mais parecida
// com WORD. Calcula-se a pontuação baseada na "maior sequencia" de caracteres
// provenientes de WORD em cada palavra de DICT.
// Após isso, acha a maior pontuação e imprime o valor relacionado a ela
void printClosestWord(char *word, char **dict, int dictSize) {
int *points = calloc(dictSize, sizeof(int));
int res = 0;
// Para cada palavra no dicionário
for (int i = 0; i < dictSize; i++) {
// Para cada letra da palavra
for (int j = 0; j < strlen(dict[i]); j++) {
// Para cada letra da substring/word
for (int k = 0; k < strlen(word); k++) {
// Checa se a letra de WORD é igual a letra da palavra sendo avaliada
// Se for igual, conta quantas letras em sequência pertencem as duas palavras
if (word[k] == dict[i][j]) {
res = 0;
for (int m = 0; m < strlen(word); m++) {
if (word[m] == dict[i][j + m]) {
res++;
}
}
// Checa se a pontuação atual é maior que a pontuação anterior
// Se for, a pontuação atual se torna a nova pontuação
points[i] = res > points[i] ? res : points[i];
}
}
}
}
// Checa qual palavra teve a maior pontuação
res = 0;
for (int i = 0; i < dictSize; i++) {
if (points[i] > points[res])
res = i;
// Em caso de empate, checa qual a menor palavra
else if (points[i] == points[res])
res = strlen(dict[i]) > strlen(dict[res]) ? res : i;
}
// Imprime a menor palavra
printf("%s\n", dict[res]);
free(points);
}
// Função de comparação para o qsort
int compare(const void* a,const void* b) {
return strcmp(*(char**)a, *(char**)b);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment