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: