Ver Mensaje Individual
  #4 (permalink)  
Antiguo 15/07/2013, 13:55
vosk
 
Fecha de Ingreso: agosto-2012
Mensajes: 601
Antigüedad: 12 años, 3 meses
Puntos: 83
Respuesta: carga un texto en una lista

Ok, guardas un archivo de texto en la 'cadena[1280]' y lo que quieres es separar ese texto palabra por palabra, dicho de otra forma quieres tokenizar por espacios, comas, puntos, saltos de linea y todos los signos de puntuacion que se te ocurran. Primero te redefino la estructura que guardaras en la lista:

Código C:
Ver original
  1. struct PALABRA {
  2.     char *texto;
  3.     struct tagPALABRA *siguiente;
  4. };
  5. typedef struct PALABRA PALABRA;
  6. typedef struct PALABRA *LISTA;

Ahora una vez leido el archivo tienes algo asi:

Código C:
Ver original
  1. LISTA lista;
  2. char cadena [] = "Esto es una prueba de texto, para ver como funciona esto de las listas. Otra linea de texto.";

Lo siguiente es eso de tokenizar; creas una funcion que se encargue de ello a la que le envias el texto y te retorna una LISTA con las palabras encontradas. Primero defines los caracteres por los que quieres cortar:

Código C:
Ver original
  1. #define TOKENCHARS " ,.;:"

Y ahora tokenizas:

Código C:
Ver original
  1. LISTA crea_lista(char *texto) {
  2.     LISTA lista = 0;
  3.     char *pch;
  4.  
  5.     pch = strtok(texto, TOKENCHARS);
  6.     while(pch) {
  7.        
  8.         //en pch tienes la palabra de este bucle
  9.         //aqui la guardaras en la lista
  10.        
  11.         //buscas la siguiente
  12.         pch = strtok(0, TOKENCHARS);
  13.     }
  14.  
  15.     return lista;
  16. }

Para cada while obtienes una palabra del texto 'cadena', y para cada palabra (es decir para cada pch) tienes que insertarla en la lista. Pues haces otra funcion que se encargue de ello, esta nueva funcion recibe el texto y un puntero a la lista, de forma que crea una nueva estructura PALABRA, la rellena con el texto proporcionado (que será cada pch encontrado en 'crea_lista') e inenta añadirla al final de la lista; si la lista está vacía se asigna como primer y unico elemento, si tiene elementos se busca el ultimo y se añade como siguiente de ese ultimo:

Código C:
Ver original
  1. char inserta_palabra(char *texto, LISTA *lista) {
  2.     PALABRA *palabra, *ptr;
  3.  
  4.     if(!(palabra = malloc(sizeof(PALABRA)))) {
  5.         return 0;
  6.     }
  7.  
  8.     palabra->texto = texto;//ojo con esto: solo lectura
  9.     palabra->siguiente = 0;
  10.  
  11.     if(!(ptr = *lista)) {
  12.         *lista = palabra;
  13.     }
  14.     else {
  15.         while(ptr->siguiente) {
  16.             ptr = ptr->siguiente;
  17.         }
  18.         ptr->siguiente = palabra;
  19.     }
  20.  
  21.     return 1;
  22. }

Ojo una nota: cuando asignas el texto proporcionado al texto de la palabra lo hago como solo lectura, es decir no deberas escribir encima del texto que hay en las estructuras; obviamente puedes cambiarlo y usar un char[100] y copiar el texto, o bloquear con malloc la longitud de texto necesaria, solo te propongo una idea facil.

Ahora implementas dentro de la funcion 'crea_lista' la llamada a esta funcion para cada pch que encuentras en el ciclo while:

Código C:
Ver original
  1. inserta_palabra(pch, &lista);

O ya que te propongo una funcion de insercion con control de error para memoria no disponible puedes aprovechar e implementar esta llamada:

Código C:
Ver original
  1. if(!inserta_palabra(pch, &lista)) {
  2.     elimina_lista(&lista);
  3.     break;
  4. }

Junto con la funcion de implementar la lista necesitas la que te libere la memoria bloqueada para esa lista, lo que hace es recorrer la lista, liberar la memoria bloquedad para cada nodo y finalmente asignar nulo a la lista:

Código C:
Ver original
  1. void elimina_lista(LISTA *lista) {
  2.     PALABRA *ptr, *sig;
  3.     ptr = *lista;
  4.     while(ptr) {
  5.         sig = ptr->siguiente;
  6.         free(ptr);
  7.         ptr = sig;
  8.     }
  9.     *lista = 0;
  10. }

Ya tienes la lista. Antes de seguir te intereserá comprobar si ha funcionado, debes implementar una funcion que recorra esa lista:
Código C:
Ver original
  1. void muestra_lista(LISTA lista) {
  2.     LISTA ptr;
  3.  
  4.     if(!(ptr = lista)) {
  5.         printf("Lista vacia.");
  6.     }
  7.     else {
  8.         while(ptr) {
  9.             printf("%s\n", ptr->texto);
  10.             ptr = ptr->siguiente;
  11.         }
  12.     }
  13. }

Ahora vuelves al main y haces la prueba:

Código C:
Ver original
  1. LISTA lista;
  2. char cadena [] = "Esto es una prueba de texto, para ver como funciona esto de las listas. Otra linea de texto.";
  3.  
  4. if((lista = crea_lista(cadena))) {
  5.     muestra_lista(lista);
  6.     elimina_lista(&lista);
  7. }

Lo siguiente es la funcion que busca palabras en la lista; hace lo mismo que la de mostrar las palabras pero en vez de printarlas las compara con la palabra proporcionada, en caso de colision incrementa un contador y lo retorna al final:

Código C:
Ver original
  1. int encuentra_palabra(char *texto, LISTA lista) {
  2.     LISTA ptr = lista;
  3.     int ctd = 0;
  4.  
  5.     while(ptr) {
  6.         if(!strcmp(texto, ptr->texto)) {
  7.             ctd++;
  8.         }
  9.         ptr = ptr->siguiente;
  10.     }
  11.  
  12.     return ctd;
  13. }

Para la llamada solo tienes que proporcionarle un texto y una lista sobre la que trabajar, te retornará el numero de colisiones:

Código C:
Ver original
  1. int q;
  2. q = encuentra_palabra("de", lista);

Seguramente te habras fijado en que strcmp es 'case sensitive', es decir que 'hola' es diferente de 'Hola'; algunas librerias proporcionan una strcmp insensitiva (pero que no es estandar), aqui te dejo una implementacion que encontré por ahi (perdon no recuerdo de donde la saqué, tendria que citar el autor)

Código C:
Ver original
  1. int stricmp (const char *p1, const char *p2) {
  2.   register unsigned char *s1 = (unsigned char *) p1;
  3.   register unsigned char *s2 = (unsigned char *) p2;
  4.   unsigned char c1, c2;
  5.  
  6.   do
  7.   {
  8.       c1 = (unsigned char) toupper((int)*s1++);
  9.       c2 = (unsigned char) toupper((int)*s2++);
  10.       if (c1 == '\0')
  11.       {
  12.             return c1 - c2;
  13.       }
  14.   }
  15.   while (c1 == c2);
  16.  
  17.   return c1 - c2;
  18. }

Ahora puedes implementar el buscador con ambas funciones y añadir un argumento que permita la busqueda sensitiva/insensitiva:

Código C:
Ver original
  1. int encuentra_palabra(char *texto, LISTA lista, char ci) {
  2.     LISTA ptr = lista;
  3.     int ctd = 0;
  4.  
  5.     while(ptr) {
  6.         if(ci) {
  7.             if(!stricmp(texto, ptr->texto)) {
  8.                 ctd++;
  9.             }
  10.         }
  11.         else {
  12.             if(!strcmp(texto, ptr->texto)) {
  13.                 ctd++;
  14.             }
  15.         }
  16.         ptr = ptr->siguiente;
  17.     }
  18.  
  19.     return ctd;
  20. }

En la llamada solo le indicas 0 para sensitive, o 1 para insensitive
Código C:
Ver original
  1. LISTA lista;
  2. char cadena [] = "Hola que tal hola qué TAL";
  3. int q;
  4.  
  5. if((lista = crea_lista(cadena))) {
  6.     q = encuentra_palabra("hola", lista, 0);
  7.     printf("%d\n", q);//muestra 1
  8.  
  9.     q = encuentra_palabra("hola", lista, 1);
  10.     printf("%d\n", q);//muestra 2
  11.  
  12.     elimina_lista(&lista);
  13. }


Saludos
vosk