001: #include<stdio.h>
002: #include<stdlib.h>
003: #include<string.h>
004: #include<ctype.h>
005:
006: char *leggi_parola(FILE*);
007: int doppia(char *);
008: int assonante(char *);
009:
010: int main(int argc, char **argv){
011:
012: char nomefile[10000]="promr.txt";
013: printf("Inserisci il nome di un file: ");
014: scanf("%s", nomefile);
015:
016: FILE *txt=fopen(nomefile, "r");
017: if(!txt)
018: {
019: perror("");
020: exit(1);
021: }
022:
023: char *parola; // vi memorizzo stringa restituita da leggi_parola()
024: char **parole = NULL; // array di stringhe con puntatori a puntatori
025: int nparole=0; // numero di parole presenti nel file
026: while(parola=leggi_parola(txt))
027: {
028: // FASE 1: cerco la parola nell'array di stringhe
029: int trovata = 0;
030: for(int i=0; i<nparole; ++i)
031: if(!strcmp(parola, parole[i])) // confronto parola restituita con i-esima parola nell'array
032: {
033: trovata = 1; // se c'era, segno di averla trovata e termino for()
034: break;
035: }
036:
037: if(!trovata) // se non c'e' la memorizzo
038: {
039: // devo allargare array di stringhe
040: parole = realloc(parole, sizeof(char*) * (nparole + 1));
041: // imposto parola letta come ultimo elemento array di stringhe (non necessaria la copia fisica della stringa visto che ogni vola leggi_parola() restituisce stringa allocata dinamicamente
042: parole[nparole] = parola;
043: // incremento numero di parole in array di stringhe
044: ++nparole;
045: //printf("%s ", parola); // debug
046: }
047: }
048: printf("\n");
049:
050: // FASE 2: scandisco array di stringhe e verifico le parole doppie
051: printf("Le parole doppie presenti nel file sono:\n");
052: for(int i=0; i<nparole; ++i)
053: if(doppia(parole[i]))
054: printf(" - %s\n", parole[i]);
055:
056: // FASE 2: scandisco array di stringhe e verifico le parole assonanti
057: printf("Le parole assonanti presenti nel file sono:\n");
058: for(int i=0; i<nparole; ++i)
059: if(assonante(parole[i]))
060: printf(" - %s\n", parole[i]);
061:
062:
063:
064: return 0;
065: }
066:
067: char *leggi_parola(FILE* f)
068: {
069: char parola[10000]; // buffer sufficientemente largo per leggere la parola dal file
070: char pulita[10000]; // buffer per depositare le sole lettere del file
071:
072: // devo leggere una parola ovvero una stringa separata da spaziature e poi rimuovere tutti i caratteri che non siano lettere
073: // qualora io legga qualcosa che NON contiene caratteri devo rileggere, per questo motivo entro in un ciclo infinito da cui esco se
074: // e solo se: arrivo a fine file oppure ho letto una parola che contiene almeno una lettera
075: while(1)
076: {
077: if(fscanf(f, " %s", parola) != 1) // leggo una "parola dal file", se non riesco vuol dire che sono arrivato alla fine e restituisco NULL
078: return NULL;
079:
080: // trasformo lettere maiuscole in minuscole
081: for(int i = 0; i< strlen(parola); ++i)
082: {
083: parola[i] = tolower(parola[i]); // per comodita' uso ctype.h, potevo anche usare una cosa del tipo
084: //if(parola[i] >= 'A' && parola[i] <= 'Z') parola[i] = parola[i] + 32;
085: }
086:
087: // copio le sole lettere nel secondo array, saltando eventuali caratteri (questo ciclo poteva benissimo essere unito al precedente)
088: int ip = 0; // indice per secondo array
089: for(int i = 0; i< strlen(parola); ++i)
090: {
091: if(isalpha(parola[i]))
092: {
093: pulita[ip] = parola[i]; // copio carattere nel secondo array e aggiorno relativo contatore
094: ++ip;
095: }
096: }
097: pulita[ip] = '\0'; // metto carattere di terminazione all'array con le sole lettere di modo che sia a tutti gli effetti una stringa
098:
099: // devo controllare che effettivamente siano rimasti dei caratteri
100: if(strlen(pulita))
101: {
102: char *p = malloc(strlen(pulita) + 1);
103: strcpy(p, pulita);
104: return p;
105: }
106: }
107:
108: }
109:
110: int doppia(char *s)
111: {
112: // parole con un numero di carattreri dispari non possono essere doppie
113: if(strlen(s)%2)
114: return 0;
115:
116: int mid = strlen(s)/2;
117:
118: // confronto i caratteri della prima meta' della stringa con quelli della seconda meta'. Mi fermo non appena pesco la prima differenza
119: for(int i=0; i<mid; ++i)
120: if(s[i] != s[i+mid])
121: return 0;
122:
123: // se arrivo qui i caratteri della prima meta' sono uguali a quelli della seconda
124: return 1;
125: }
126:
127: int assonante(char *s)
128: {
129:
130: // parole con un numero di caratteri pari non possono essere assonanti, escludo anche le parole costituite da una singola lettera
131: if(!strlen(s)%2 || strlen(s) == 1)
132: return 0;
133:
134: // uso questo trucco, elimino l'ultima lettera della stringa e mi limito a verificare che cio' che rimane sia doppio
135: int indiceultimalettera = strlen(s) - 1;
136: char ultima = s[indiceultimalettera]; // pero' la memorizzo per poterla rimettere
137: s[indiceultimalettera] = '\0'; // elimino ultima lettera stringa sostituendola con il terminatore di stringa
138: int ris = doppia(s); // in ris, vero o falso a seconda che il primo pezzo sia doppio
139: s[indiceultimalettera] = ultima;
140:
141: return ris;
142:
143: }
144:
145: