Il programma funziona bene nel complesso; tuttavia, incontra un problema quando elabora parole accentate. Quando il programma incontra parole con caratteri accentati, smette di funzionare correttamente. La ragione esatta di questa interruzione non è chiara, e sono necessari ulteriori debug per identificare la causa di questo problema con le parole accentate.
Attraverso alcuni debug con varie print inserite qua e là, ho potuto circoscrivere che il problema risiede nella funzione readCharacters quando legge carattere per carattere.
Il programma accetta solo librerie standard C e dev funzionare su macchine Unix-like (no Windows) o kernel Linux. È progettato per leggere un file di testo italiano che può contenere caratteri speciali come ., ?, ! e '. Scansiona le parole nel testo e le aggiunge a un file CSV, mantenendo la frequenza di ciascuna parola. Il programma utilizza una matrice per memorizzare le parole e le loro rispettive frequenze e coordinate, mentre una struttura a dizionario viene utilizzata per gestire l'alfabeto e i sotto-alfabeti.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include <wchar.h>
#include <wctype.h>
#include <locale.h>
// Definizione della struttura per un oggetto contenente una Stringa, la sua frequenza, e le coordinate nella matrice
typedef struct {
wchar_t Stringa[31]; // Stringa di massimo 30 caratteri più il terminatore null
float frequenza; // Frequenza della parola
int occorrenza; // Numero di occorrenze della parola
int x; // Coordinata x nella matrice
int y; // Coordinata y nella matrice
} oggetto;
// Definizione della struttura per una matrice contenente una lista di oggetti e le sue dimensioni
typedef struct {
oggetto** lista; // Lista di oggetti (matrice)
int* x; // Array delle dimensioni delle righe
int y; // Numero di righe
} matrice;
// Definizione della struttura per l'alfabeto contenente un sottoalfabeto e una parola
struct Alfabeto {
struct Alfabeto* sottoalfabeto[46]; // Sottoalfabeto (array di puntatori ad altre strutture Alfabeto)
oggetto* parola; // Parola associata al nodo dell'alfabeto
};
// Definizione del tipo Dizionario come un puntatore a struct Alfabeto
typedef struct Alfabeto Dizionario;
// Dichiarazione delle funzioni
Dizionario* deallocazione(Dizionario* diz);
void stampaMatrice(matrice* matrix, FILE* foglio);
int indiceAscii(wchar_t carattere);
bool confrontaStringhe(wchar_t* Stringa1, wchar_t* Stringa2);
int fineStringa(wchar_t Stringa1[], matrice* matrix, Dizionario* diz, int fine);
void leggiCaratteri(FILE* file, matrice* matrix, Dizionario* dizionario);
int main() { // Funzione principale
setlocale(LC_ALL, "it_IT.UTF-8"); // Imposta una locale che supporta Unicode
FILE* file = fopen("prova.txt", "r"); // Apre il file di input in lettura
FILE* foglio = fopen("controprova.csv", "w"); // Apre il file di output in scrittura
if (file == NULL || foglio == NULL) { // Se uno dei file non si apre
exit(EXIT_FAILURE); // Esce con errore
}
Dizionario* dizionario = (Dizionario*)calloc(1,sizeof(Dizionario)); // Alloca il dizionario
dizionario->parola = (oggetto*)calloc(1,sizeof(oggetto)); // Alloca una parola nel dizionario
matrice matrix;
matrix.y = 1; // Inizializza il numero di righe della matrice
matrix.x = (int*)calloc(1,sizeof(int)); // Alloca memoria per l'array delle dimensioni delle righe
matrix.x[0] = 1; // Inizializza la dimensione della prima riga
matrix.lista = (oggetto**)calloc(1,matrix.y * sizeof(oggetto*)); // Alloca memoria per la matrice
matrix.lista[matrix.y - 1] = (oggetto*)calloc(1,2 * sizeof(oggetto)); // Alloca memoria per una riga della matrice
leggiCaratteri(file, &matrix, dizionario); // Chiama la funzione leggiCaratteri
stampaMatrice(&matrix, foglio); // Chiama la funzione stampaMatrice
fclose(foglio); // Chiude il file di output
fclose(file); // Chiude il file di input
for (int i = 0; i < matrix.y -1; i++) { // Libera la memoria allocata per la matrice
free(matrix.lista[i]);
}
free(matrix.lista);
free(matrix.x);
for (int i = 0; i < 46; i++) { // Libera la memoria del dizionario
dizionario->sottoalfabeto[i] = deallocazione(dizionario->sottoalfabeto[i]); // Chiama la funzione deallocazione
}
free(dizionario->parola); // Libera la memoria della parola
free(dizionario); // Libera la memoria del dizionario
return 0; // Ritorna 0
}
Dizionario* deallocazione(Dizionario* diz) { // Funzione per deallocare la memoria del dizionario
if (diz == NULL) { // Se il dizionario è NULL
return NULL; // Ritorna NULL
}
for (int i = 0; i < 46; i++) { // Scorre i 46 elementi del sottoalfabeto
diz->sottoalfabeto[i] = deallocazione(diz->sottoalfabeto[i]); // Chiama la funzione deallocazione ricorsivamente
}
free(diz->parola); // Libera la memoria della parola
free(diz); // Libera la memoria del dizionario
return NULL;
}
int indiceAscii(wchar_t carattere) { // Funzione per ottenere l'indice ASCII di un carattere
// Converte il carattere in minuscolo
wchar_t c = towlower(carattere);
if (iswalpha(c)) { // Gestisce le lettere non accentate
return c - L'a';
} else { // Gestisce i caratteri accentati
switch (c) {
case L'à': return 26;
case L'è': return 27;
case L'é': return 28;
case L'ì': return 29;
case L'ò': return 30;
case L'ù': return 31;
case L'!': return 32;
case L'?': return 33;
case L'.': return 34;
case L'\'': return 35;
}
}
// Gestisce i numeri
if (c >= L'0' && c <= L'9') {
return 36 + (c - L'0');
}
// Carattere non riconosciuto
return -1;
}
// Funzione per confrontare due stringhe
bool confrontaStringhe(wchar_t* Stringa1, wchar_t* Stringa2) {
if (*Stringa1 == L'\0' && *Stringa2 == L'\0') { // Se entrambe le stringhe sono terminate
return true; // Ritorna true
}
if (*Stringa1 == *Stringa2 || (towlower((wchar_t)*Stringa1) == towlower((wchar_t)*Stringa2))) { // Controlla se i caratteri sono uguali o se sono uguali in minuscolo
return confrontaStringhe(Stringa1 + 1, Stringa2 + 1); // Richiama la funzione sul prossimo carattere
}
return false; // Se i caratteri non sono uguali, ritorna false
}
// Funzione per la ricerca operativa di una Stringa nella matrice
bool ricercaOperativa(wchar_t Stringa[], int indice, Dizionario* diz, int i, int p, matrice* m) {
Dizionario* dizAttuale = diz; // Inizializza dizAttuale con diz
int ASCII; // Dichiara la variabile ASCII
if (Stringa[indice] == L'\0') { // Se il carattere corrente è il terminatore di Stringa
if (confrontaStringhe(dizAttuale->parola->Stringa, m->lista[i][0].Stringa)) { // Se la Stringa della parola del dizionario è uguale alla Stringa della matrice
int n = 1;
int y = dizAttuale->parola->y;
int x = dizAttuale->parola->x;
int trovato = 0;
m->lista[y][0].occorrenza++;
while (n <= m->x[y] && m->lista[y][n].x == n) { // Finché n è minore o uguale alla dimensione x della matrice e l'elemento della matrice è uguale a n
if (confrontaStringhe(m->lista[y][n].Stringa, m->lista[i][p].Stringa)) { // Se la Stringa corrente è uguale alla Stringa della matrice
m->lista[y][n].occorrenza++; // Incrementa l'occorrenza
m->lista[y][n].frequenza = (float)m->lista[y][n].occorrenza / (float)m->lista[y][0].occorrenza; // Calcola la frequenza
trovato = 1; // Imposta trovato a 1
}
m->lista[y][n].frequenza = (float)m->lista[y][n].occorrenza / (float)m->lista[y][0].occorrenza; // Calcola la frequenza
n++; // Incrementa n
}
if (!trovato) {
if (n > m->x[y]) {
m->x[y] = n;
}
m->lista[y] = realloc(m->lista[y], (n + 1) * sizeof(oggetto)); // Rialloca la memoria per la riga
wcscpy(m->lista[y][n].Stringa, m->lista[i][p].Stringa); // Copia la Stringa nella matrice
m->lista[y][n].occorrenza = 1; // Inizializza l'occorrenza a 1
m->lista[y][n].frequenza = (float)m->lista[y][n].occorrenza / (float)m->lista[y][0].occorrenza; // Calcola la frequenza
m->lista[y][n].x = n; // Assegna n alla coordinata x
}
return true; // Ritorna true
}
wcscpy(dizAttuale->parola->Stringa, Stringa); // Copia la Stringa nella parola del dizionario
dizAttuale->parola->x = p; // Assegna p alla coordinata x della parola
dizAttuale->parola->y = i; // Assegna i alla coordinata y della parola
m->lista[i][1].x = 1; // Assegna 1 alla coordinata x della matrice
m->lista[i][0].x = 0; // Assegna 0 alla coordinata x della matrice
m->lista[i][1].occorrenza = 1; // Inizializza l'occorrenza a 1
m->lista[i][0].occorrenza = 1; // Inizializza l'occorrenza a 1
m->lista[i][1].frequenza = (float)m->lista[i][1].occorrenza / (float)m->lista[i][0].occorrenza; // Calcola la frequenza
return false; // Ritorna false
}
ASCII = indiceAscii(Stringa[indice]); // Calcola l'indice ASCII del carattere corrente
if (dizAttuale->sottoalfabeto[ASCII] == NULL) { // Se il sottoalfabeto corrente è NULL
dizAttuale->sottoalfabeto[ASCII] = (Dizionario*)calloc(1,sizeof(Dizionario)); // Alloca memoria per il sottoalfabeto
if (dizAttuale->sottoalfabeto[ASCII] == NULL) { // Se la memoria non è stata allocata
exit(1); // Esce con errore
}
dizAttuale->sottoalfabeto[ASCII]->parola = (oggetto*)calloc(1,sizeof(oggetto)); // Alloca memoria per la parola del sottoalfabeto
if (dizAttuale->sottoalfabeto[ASCII]->parola == NULL) { // Se la memoria non è stata allocata
exit(1); // Esce con errore
}
}
dizAttuale = dizAttuale->sottoalfabeto[ASCII]; // Assegna il sottoalfabeto corrente a dizAttuale
return ricercaOperativa(Stringa, indice + 1, dizAttuale, i, p, m); // Richiama la funzione ricorsivamente
}
// Funzione per gestire la fine di una Stringa
int fineStringa(wchar_t Stringa1[], matrice* matrix, Dizionario* diz, int fine) {
if (Stringa1[0] == L'\0') { // Se la Stringa è vuota
return 0; // Ritorna 0
}
wcscpy(matrix->lista[matrix->y - 1][1].Stringa, Stringa1); // Copia la Stringa nella matrice
matrix->lista[matrix->y - 1][1].x = 1; // Assegna 1 alla coordinata x in posizione 1
matrix->lista[matrix->y - 1][0].x = 0; // Assegna 0 alla coordinata x in posizione 0
int controllo = ricercaOperativa(matrix->lista[matrix->y - 1][0].Stringa, 0, diz, matrix->y - 1, 1, matrix); // Chiama la funzione ricercaOperativa
if (controllo == 0) {
matrix->y++;
matrix->lista = realloc(matrix->lista, matrix->y * sizeof(oggetto*)); // Rialloca memoria per la matrice
matrix->x = realloc(matrix->x, matrix->y * sizeof(int));
matrix->x[matrix->y - 1] = 1;
matrix->lista[matrix->y - 1] = (oggetto*)calloc(1,2 * sizeof(oggetto));
}
wcscpy(matrix->lista[matrix->y - 1][0].Stringa, Stringa1); // Copia la Stringa nella matrice
if (fine == 1) { // Se fine è 1
wcscpy(matrix->lista[matrix->y - 1][1].Stringa, matrix->lista[0][0].Stringa); // Copia la Stringa iniziale nella matrice
int controllo = ricercaOperativa(matrix->lista[matrix->y - 1][0].Stringa, 0, diz, matrix->y - 1, 1, matrix); // Chiama la funzione ricercaOperativa
return 0; // Ritorna 0
}
Stringa1[0] = L'\0'; // Resetta la Stringa
return 0; // Ritorna 0
}
// Funzione per leggere i caratteri dal file e gestire la Stringa temporanea
void leggiCaratteri(FILE* file, matrice* matrix, Dizionario* dizionario) {
wchar_t Stringa1[31]; // Dichiara una Stringa di 30 caratteri
int indice = 0; // Inizializza l'indice a 0
wchar_t carattere; // Dichiara la variabile carattere
int primaParola = 0;
const wchar_t* caratteriAccentati = L"àèéìòóùÀÈÉÌÒÓÙ";
while ((carattere = fgetwc(file))) { // Legge il carattere dal file
wchar_t successivo = fgetwc(file); // Legge il prossimo carattere
fseek(file, -1, SEEK_CUR); // Riposiziona il cursore del file indietro di un carattere
if ((carattere == L' '||carattere ==L'\n') && successivo == WEOF) {
// Aggiunge la parola al dizionario per evitare che l'ultima parola non venga considerata come finale
wcscpy(matrix->lista[matrix->y - 1][1].Stringa, matrix->lista[0][0].Stringa); // Copia la Stringa iniziale nella matrice
ricercaOperativa(matrix->lista[matrix->y - 1][0].Stringa, 0, dizionario, matrix->y - 1, 1, matrix); // Chiama la funzione ricercaOperativa per controllare se la chiave è stata già incontrata nel testo
return;
}
// Legge la prima parola
if (primaParola == 0 && (carattere == L'\n' || carattere == L' ')) { // Se i primi caratteri sono \n o spazio saltali
continue;
} else if (primaParola == 0 && (iswalnum(carattere) || (wcschr(caratteriAccentati, carattere) != NULL))) { // Se trovi o quando troverai dei caratteri alfanumerici aggiungili alla matrice in prima posizione
matrix->lista[0][0].Stringa[indice] = carattere;
indice++;
if (successivo == L' ' || successivo == L'\n' || successivo == L'!' || successivo == L'?' || successivo == L'.') { // Se seguito da spazio o da a capo termina la Stringa
matrix->lista[0][0].Stringa[indice] = L'\0';
indice = 0;
primaParola = 1;
} else if (successivo == L'\'') { // Se seguito da apostrofo appendi l'apostrofo e termina la Stringa e la primaparola
matrix->lista[0][0].Stringa[indice] = L'\'';
matrix->lista[0][0].Stringa[indice + 1] = L'\0';
indice = 0;
primaParola = 1;
// Incrementa il cursore per impedire di leggere 2 volte l'apostrofo
fseek(file, 1, SEEK_CUR);
}
continue;
} else if (primaParola == 0 && (carattere == L'!' || carattere == L'?' || carattere == L'.')) { // Se incontri dei caratteri speciali aggiungili alla matrice come dei caratteri a sé
matrix->lista[0][0].Stringa[indice] = carattere;
matrix->lista[0][0].Stringa[indice + 1] = L'\0';
primaParola = 1;
indice = 0;
continue;
}
if (carattere == L'!' || carattere == L'?' || carattere == L'.') {
if (indice > 0) {
Stringa1[indice] = L'\0';
fineStringa(Stringa1, matrix, dizionario, 0); // Chiama la funzione fineStringa
indice = 0;
}
Stringa1[0] = carattere;
Stringa1[1] = L'\0';
if (successivo == WEOF) {
fineStringa(Stringa1, matrix, dizionario, 1); // Chiama la funzione fineStringa con il parametro fine a 1
break;
}
fineStringa(Stringa1, matrix, dizionario, 0);
indice = 0;
} else if (iswalnum(carattere) || (wcschr(caratteriAccentati, carattere) != NULL) || carattere == L'\'') {
Stringa1[indice++] = carattere; // Aggiunge il carattere alla Stringa
wprintf(L"%lc", carattere); // Stampa il carattere
if (successivo == L' ' || successivo == L'\n' || successivo == WEOF ||
successivo == L'!' || successivo == L'?' || successivo == L'.' || carattere == L'\'') {
Stringa1[indice] = L'\0';
fineStringa(Stringa1, matrix, dizionario, (successivo == WEOF) ? 1 : 0); // Chiama la funzione fineStringa
indice = 0;
}
} else if (carattere == L' ' || carattere == L'\n') {
if (indice > 0) {
Stringa1[indice] = L'\0';
fineStringa(Stringa1, matrix, dizionario, 0); // Chiama la funzione fineStringa
indice = 0;
}
} else if (!(iswalnum(carattere) || (wcschr(caratteriAccentati, carattere) != NULL) ||
carattere == L'\'' || carattere == L'!' ||
carattere == L'?' || carattere == L'.') &&
successivo == L' ' || successivo == L'\n') {
if (indice > 0) {
Stringa1[indice] = L'\0';
fineStringa(Stringa1, matrix, dizionario, 0); // Chiama la funzione fineStringa
indice = 0;
}
continue;
}
if (successivo == WEOF) { // Se raggiunge la fine del file
break;
}
}
return;
}
// Funzione per stampare la matrice sul file
void stampaMatrice(matrice* matrix, FILE* foglio) {
for (int i = 0; i <= matrix->y - 1; i++) {
if (matrix->lista[i][1].frequenza == 0) {
return;
}
fwprintf(foglio, L"%ls", matrix->lista[i][0].Stringa); // Stampa la prima colonna (parola)
for (int j = 1; j <= matrix->x[i]; j++) {
fwprintf(foglio, L",%ls,%.4f", matrix->lista[i][j].Stringa, matrix->lista[i][j].frequenza); // Stampa la parola e la sua frequenza
}
if (i != matrix->y - 1) {
fwprintf(foglio, L"\n");
}
}
}