Autor
|
Tema: Extraer palabras de un texto leido en un archivo (en C) (Leído 4,501 veces)
|
Locura_23
Desconectado
Mensajes: 162
|
Buenas a todos, resulta que estoy teniendo un error con este codigo, tal vez no estoy viendo algo o me falta un concepto. La idea seria leer un texto por usuario y guardarlo en un archivo binario, segundo, mostrarlo por consola, y lo mas importante extraer todas y cada una de las palabras del texto ingresado por usuario. Ahora bien, tengo entendido que los archivos binarios son mejores para guardar registros ( estructuras) y los archivos txt para texto. Lamentablemente, me piden que sean archivos binarios... Cosa que no le veo mucho sentido. El error es que si ingreso un texto de mas de 3 o 4 palabras aveces algunas palabras se muestran con basura. Por ejemplo si ingreso "la casa roja y el perro blanco" no hay problema. Si ingreso "la raiz cuadrada de una potencia" entonces la palabra "cuadrada" muestra basura tambien. Esto por poner algunos ejemplos. Este el codigo, (por cierto mucho que mejorar) gracias, saludos. #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define ARCH0 "arch0.bin" #define TAM_MAX 1000 void crearArchivo() { FILE * pfile = fopen(ARCH0 , "wb"); char texto[TAM_MAX]; if( pfile ) { printf("\nIngrese el texto:\n"); fwrite(&texto ,sizeof(texto ),1,pfile ); } } void mostrarArchivo() { FILE * pfile = fopen(ARCH0 , "rb"); char texto[TAM_MAX]; if( pfile ) { fread(&texto , sizeof(texto ),1,pfile ); } } void limpiarArreglo(char a[],int j) { while( j - 1 >= 0 ) { a[j] = 0; j--; } } void archivoToDic() { FILE * pfile = fopen(ARCH0 ,"rb"); char texto[TAM_MAX]; int i = 0; /**contador texto*/ char aux[30]; /**para guardar cada termino del texto*/ int j = 0; /**contador string aux*/ if( pfile ) { fread(&texto , sizeof(texto ),1,pfile ); { { /*copia cada letra leida distinta de espacio a la cadena auxiliar*/ aux[j] = texto[i]; j++; i++; } /*tras salir del while, aux contiene 1 palabra del texto, es decir, los caracteres hasta el primer espacio encontrado*/ /*limpiar el arreglo y volver el contador j a 0*/ while( j - 1 >= 0 ) { aux[j] = 0; j--; } j = 0; /*el proceso sigue con todos los terminos*/ i++; } } } int main() { crearArchivo(); printf("\nContenido Archivo:\n"); mostrarArchivo(); archivoToDic(); return 0; }
Por ultimo decir que pense como solucion utilizar memoria dinamica de manera que solo se guarden en el archivo estrictamente los caracteres del texto ingresado y no otra basura que me pueda estar guardando. qué opinan al respecto?
|
|
« Última modificación: 21 Noviembre 2022, 14:46 pm por Locura_23 »
|
En línea
|
|
|
|
K-YreX
|
Tras un par de pruebas, todo parece indicar que a partir de palabras con 8 caracteres, se muestra basura al final. De todas formas, aunque en alguna ocasión no se vea basura, no significa que el funcionamiento sea correcto. Por lo tanto, vamos a verlo... Respondiendo a tu pregunta final: Se podría usar memoria dinámica? Sí. Es necesario? No. Ahora lo vas a ver... Parte 1: Crear fichero (a partir de aquí vamos a suponer que introduzco "hola") Aquí ya podemos hacer varias mejoras: - Por un lado, vamos a reemplazar la función gets() por fgets(). Es la versión "segura" de gets() para evitar problemas si nos pasamos del tamaño máximo de la variable: fgets(texto, TAM_MAX, stdin)
Con esto le estamos diciendo: guarda en <texto> los primeros TAM_MAX-1 (como mucho) caracteres obtenidos de stdin (entrada estándar). Si hay menos, guardará los que haya y si hay más, los ignorará y los dejará en el buffer (he aquí la magia mejorada en contra de gets())
- Y por qué guarda TAM_MAX-1 caracteres si la capacidad es TAM_MAX? Porque al final siempre va a incluir "a terminating null character" (\0) que indica el fin de la cadena. En C siempre se indica el fin de una cadena de chars con un '\0'. Se nos habrá guardado en <texto> = {'h', 'o', 'l', 'a', '\0', ...}
- fgets() almacena el carácter '\n' al pulsar Enter. Antes te engañé, en 'texto' se guardó = {'h', 'o', 'l', 'a', '\n', '\0', ...} Esto se puede solucionar de la siguiente manera:
fgets(texto , SIZE , stdin ); // En mi opinion, este fragmento deberia ir practicamente siempre despues de un fgets() usando stdin como entrada if(texto [strlen(texto ) - 1] == '\n') // Si el ultimo caracter guardado (strlen devuelve el numero de chars hasta encontrar un '\0') es un Enter, significa que no queda nada en el buffer texto [strlen(texto ) - 1] = '\0'; // Adelanta el '\0' y sobreescribe el Enter (da igual todo lo que haya despues)else // Y si no es Enter, significa que nos hemos pasado de longitud y han quedado cosas en el buffer, entre ellas el Enter while(getchar() != '\n'); // entonces consumimos el buffer para dejarlo limpio y evitar errores futuros.
- Por otro lado, cuando escribimos el contenido en el fichero, tenemos que indicar el número de bytes que queremos escribir.
En lugar de indicar sizeof(texto) que escribiría 1000 bytes en el fichero, vamos a indicar strlen(texto) para escribir sólo 4. Ves, no hacía falta usar memoria dinámica Escribiendo strlen(texto) estaremos escribiendo EXACTAMENTE lo que el usuario introdujo, ni un carácter más ni uno menos. (Puedes usar un editor hexadecimal o un editor que muestre caracteres no imprimibles para ver el contenido exacto del fichero) Ahora tenemos esto:
void crearArchivo() { FILE * pfile = fopen(ARCH0 , "wb"); char texto[TAM_MAX]; if( pfile ) { printf("\nIngrese el texto:\n"); fgets(texto , TAM_MAX , stdin ); if(texto [strlen(texto ) - 1] == '\n') texto [strlen(texto ) - 1] = '\0'; } }
Parte 2: Mostrar ficheroAquí tenemos que leer el contenido del fichero. Lo importante es que no se nos cuele basura después del texto que hay dentro del fichero. La solución más sencilla es inicializar el array de chars con 0s. 0 es el valor numérico del carácter nulo (0 = '\0') De esta manera, con fread leeremos el contenido del fichero y el resto de espacio que sobre en el array ya estará rellenada con 0s por lo que no mostraremos ninguna basura. char texto[TAM_MAX] = {0}; if(pfile) { fread(texto , TAM_MAX , 1, pfile ); }
Parte 3... Está es para ti que sino menudo aburrimiento si no puedes probarlo tú mismo
|
|
|
En línea
|
cout << "Todos tenemos un defecto, un error en nuestro código" << endl;
|
|
|
Locura_23
Desconectado
Mensajes: 162
|
Qué crack ! Gracias maestro, la verdad me ayudaste un monton. Continué programando igual el sistema porque con parrafos omitia la basura al parecer, pero era un poco incierto el funcionamiento jaja, pero ahora parece más estable. Lo de inicializar el arreglo con ceros fue clave, y reescribi el programa con memoria estatica, y de momento no me esta mostrando basura como antes. Lo que sí se me volvio a romper en la parte donde reemplacé sizeof() por strlen() tanto en fwrite() como en fread(), pero voy a ver bien qué puede ser. (Te referias de usar: fwrite(&texto, sizeof(char)* strlen(texto), 1, pfile) ) ? Lo del fgets() sí voy a reemplazarla en cuanto antes, justamente por este foro me enteré de que gets() no era recomendable jaja. Lo de la parte 3 supongo que te refieres a la funcion archivoToDic()? En esa parte también inicialize el arreglo aux[20] = { 0 };
que este arreglo se utilizaba para guardar una palabra del texto general.
|
|
« Última modificación: 22 Noviembre 2022, 17:25 pm por Locura_23 »
|
En línea
|
|
|
|
K-YreX
|
Lo que sí se me volvio a romper en la parte donde reemplacé sizeof() por strlen() tanto en fwrite() como en fread(), pero voy a ver bien qué puede ser. (Te referias de usar: fwrite(&texto, sizeof(char)* strlen(texto), 1, pfile) ) ? Si te fijas bien en el código, en fread() no utilicé strlen(). Por qué? Porque strlen(texto) = 0 ya que está vacío en ese momento. Cuando lees del archivo no sabes cuántos bytes tienes que leer por eso se intenta leer el máximo disponible: TAM_MAX. Por otro lado, no hace falta multiplicar strlen(texto) por sizeof(char). Sí sería la forma correcta pero como un char ocupa 1 byte, sizeof(char) = 1. Por eso se puede omitir esa multiplicación y hacer el código un poco más sencillo. Si la pones no está mal, estaría bien porque si el tamaño de un char cambiase seguiría funcionando bien. Lo de la parte 3 supongo que te refieres a la funcion archivoToDic()? En esa parte también inicialize el arreglo aux[20] = { 0 };
que este arreglo se utilizaba para guardar una palabra del texto general. Sí, con la parte 3 me refería a la última función, que intentarás sacarla tú solo aplicando lo visto en las otras funciones. Si no lo consigues vuelve a dejar la parte que te da problemas con los avances y así poder echarle un ojo
|
|
|
En línea
|
cout << "Todos tenemos un defecto, un error en nuestro código" << endl;
|
|
|
|
Mensajes similares |
|
Asunto |
Iniciado por |
Respuestas |
Vistas |
Último mensaje |
|
|
extraer el texto de un archivo de word en java
Java
|
evatking
|
1
|
6,419
|
10 Diciembre 2009, 23:42 pm
por Leyer
|
|
|
extraer el texto de un archivo de PDF en java
Java
|
evatking
|
0
|
3,388
|
11 Diciembre 2009, 01:11 am
por evatking
|
|
|
Como extraer multiples datos de un archivo de texto[AYUDA]
Programación C/C++
|
Rastreator1010
|
0
|
2,212
|
16 Octubre 2014, 20:17 pm
por Rastreator1010
|
|
|
Problema con clase Tokenizer (contar palabras de un archivo de texto)
Java
|
jamatbar
|
2
|
3,216
|
27 Enero 2016, 09:33 am
por jamatbar
|
|
|
Extraer variable de un archivo de texto (BATCH)
Scripting
|
rafaeljoseyepez
|
5
|
12,722
|
15 Diciembre 2020, 00:18 am
por rafaeljoseyepez
|
|