elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.

 

 


Tema destacado: Curso de javascript por TickTack


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación C/C++ (Moderadores: Eternal Idol, Littlehorse, K-YreX)
| | |-+  Leer datos de un cierto formato desde un fichero
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Leer datos de un cierto formato desde un fichero  (Leído 4,058 veces)
javiepe

Desconectado Desconectado

Mensajes: 4


Ver Perfil
Leer datos de un cierto formato desde un fichero
« en: 12 Marzo 2014, 15:19 pm »

Buenas,

estoy bastante acostumbrado a programar en Fortran, pero ahora tengo un proyecto en el cual debo programar en C, y aunque tengo en mente cómo hacer el programa, me falla el proceso de lecturas de datos desde un fichero.

Tengo un fichero en el cual hay dos tipos de datos. El primer tipo tiene el siguiente formato:

AAAA-MM-DD E F

(AAAA es año, MM es mes, DD es día, E es un número entero, y F uno decimal)

El segundo tipo es muy parecido:

AAAA-MM-DD F


A mí me interesa leer los números E y F del primer grupo de datos, guardándolos en dos vectores, y leer el número F del segundo grupo de datos, guardándolo en otro vector. Aquí es donde surge mi problema.

Estoy intentando hacer esto utilizando la función fscanf, escribiendo estos dos comando después de delcarar variables y abrir los ficheros:

fscanf (f1, "%d-%d-%d %d %f\n", &ano, &mes, &dia , E1, F1);
fscanf (f1, "%d-%d-%d %f\n", &ano, &mes, &dia, F2);

He declarado E1(3000), F1(3000) y F2(3000) asegurándome de que son suficientemente grandes para almacenar todos los números que hay en el fichero.

Haciendo esto, no consigo que se almacenen los números, ni siquiera el año. No sé si la función fscanf se utiliza así o no.

Agradecería cualquier ayuda, ya que tengo el algoritmo básico en mente, pero no puedo aplicarlo por culpa de que no sé cómo leer el fichero.

Muchas gracias.


« Última modificación: 12 Marzo 2014, 15:33 pm por javiepe » En línea

rir3760


Desconectado Desconectado

Mensajes: 1.639


Ver Perfil
Re: Leer datos de un cierto formato desde un fichero
« Respuesta #1 en: 12 Marzo 2014, 17:06 pm »

Puedes utilizar la función fscanf siempre y cuando la entrada garantice solo esos dos tipos de linea y nada mas. Primero lees la fecha y a continuación verificas si el resto es uno de los dos casos.

Un ejemplo con sscanf:
Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. int main(void)
  5. {
  6.   char *linea[] = {
  7.      "1970-01-01 1 2.3",
  8.      "1970-01-01 4.5",
  9.      "1980-01-01 1 2.3",
  10.      "1980-01-01 4.5",
  11.      "1990-01-01 1 2.3",
  12.      "1990-01-01 4.5",
  13.   };
  14.   size_t num_elem = sizeof linea / sizeof linea[0];
  15.   size_t i;
  16.  
  17.   unsigned a;
  18.   unsigned m;
  19.   unsigned d;
  20.   int num_ent;
  21.   double num_pf;
  22.   int nc;
  23.  
  24.   for (i = 0; i < num_elem; i++)
  25.      if (sscanf(linea[i], "%u-%u-%u%n", &a, &m, &d, &nc) == 3){
  26.         printf("%u-%02u-%02u: ", a, m, d);
  27.  
  28.         if (sscanf(linea[i] + nc, "%d%*[ ]%lf", &num_ent, &num_pf) == 2)
  29.            printf("%d %.2f\n", num_ent, num_pf);
  30.         else if (sscanf(linea[i] + nc, "%lf", &num_pf) == 1)
  31.            printf("%.2f\n", num_pf);
  32.         else
  33.            puts("Error");
  34.      }
  35.  
  36.   return EXIT_SUCCESS;
  37. }

En tu caso solo tienes que leer el archivo linea por linea con fgets, a continuación la procesas con sscanf.

Un saludo


En línea

C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language
leosansan


Desconectado Desconectado

Mensajes: 1.314


Ver Perfil
Re: Leer datos de un cierto formato desde un fichero
« Respuesta #2 en: 12 Marzo 2014, 20:19 pm »

Me pasa un detalle para mi curioso. Con esto en el fichero:

Citar

1970-01-01 1 1.5
1970-01-01 1.15
1980-01-01 2 2.5
1980-01-01 1.225
1990-01-01 3 3.5
1990-01-01 1.35


la salida es:

Citar
5: 1 1.5
5: 1 0.15
5: 2 2.5
5: 1 0.225
5: 3 3.5
5: 1 0.35


Es decir, en el código que te pongo a continuación sólo actúa el scanf==5 y lo que hace el muy bandido es, cuando debería actuar para mi criterio el scanf==4, sigue actuando el scanf==5 y lo que hace es coger, en las líneas pares, el decimal y separarlo en la parte entera y la parte decimal y así no deja actuar al scanf==4.

¿Me podrían iluminar a ver qué diablos estoy haciendo fatal?.


Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define N 5
  4.  
  5. int main(){
  6.  int i=0,j=0,k=0,aux[3],E[N];
  7.  float F1[N],F2[N];
  8.  FILE* fichero;
  9.  fichero = fopen("fecha0.txt", "r");
  10.  if ((fichero = fopen("fecha0.txt", "r")) == NULL){
  11.    perror("fecha0.txt");
  12.    return EXIT_FAILURE;
  13.  }
  14.  while (! feof(fichero)){
  15.      if (fscanf(fichero,"%d %d %d %d %f ", &aux[0],&aux[1], &aux[2], &E[i], &F1[i])==5){
  16.        printf("5: %d %g\n", E[i], F1[i]);
  17.        i++;
  18.      }
  19.      else if (fscanf(fichero,"%d %d %d %f ", &aux[0],&aux[1], &aux[2], &F2[k])==4){
  20.        printf("4: %g\n", F2[k]);
  21.        k++;
  22.      }
  23.      else
  24.        puts("Error");
  25.  }
  26.  for (j=0;j<i;j++)
  27.    printf ("%3d  ",E[j]) ;
  28.  putchar ('\n');
  29.  for (j=0;j<i;j++)
  30.    printf ("%3g  ",F1[j]) ;
  31.  putchar ('\n');
  32.  /*for (j=0;j<k;j++)
  33.     printf ("%3g  ",F2[j]);*/
  34.  putchar ('\n');
  35.  fclose(fichero);
  36.  return EXIT_SUCCESS;
  37. }
  38.  

Obviamente el código que  cuelga rir3760 funciona, como no podría ser de otra manera al ser suyo, a las mil maravillas. La salida es:

Citar
1    2    3
1.5  2.5  3.5
1.15  1.225  1.35


Process returned 0 (0x0)

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define N 5
  4.  
  5. int main()
  6. {
  7.  int i=0,j=0,k=0,aux[3],E[N],nc;
  8.  float F1[N],F2[N];
  9.  char linea[81];
  10.  FILE* fichero;
  11.  fichero = fopen("fecha0.txt", "r");
  12.  if ((fichero = fopen("fecha0.txt", "r")) == NULL){
  13.    perror("fecha0.txt");
  14.    return EXIT_FAILURE;
  15.  }
  16.  while (! feof(fichero)){
  17.    fgets(linea, 80, fichero);
  18.      if (sscanf(linea, "%d-%d-%d%n", &aux[0], &aux[1], &aux[2], &nc) == 3){
  19.         if (sscanf(linea + nc, "%d%*[ ]%f", &E[i], &F1[i]) == 2){
  20.           i++;
  21.         }
  22.         else if (sscanf(linea + nc, "%f", &F2[k]) == 1){
  23.           k++;
  24.         }
  25.         else
  26.            puts("Error");
  27.      }
  28.  }
  29.  for (j=0;j<i;j++)
  30.    printf ("%3d  ",E[j]) ;
  31.  putchar ('\n');
  32.  for (j=0;j<i;j++)
  33.    printf ("%3g  ",F1[j]) ;
  34.  putchar ('\n');
  35.  for (j=0;j<k;j++)
  36.    printf ("%3g  ",F2[j]) ;
  37.  putchar ('\n');
  38.  fclose(fichero);
  39.  return EXIT_SUCCESS;
  40. }

Gracias de antemano.

¡¡¡¡ Saluditos! ..... !!!!




REEDITADO:

Lo he solventado de la forma más simple. Ahora la salida es la correcta:


Citar
5: 1  1.5
4: 1.15
5: 2  2.5
4: 1.225
5: 3  3.5
4: 1.35
  1    2    3
1.5  2.5  3.5
1.15  1.225  1.35


Process returned 0 (0x0)

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define N 5
  4.  
  5. int main(){
  6.  int i=0,j=0,k=0,aux[3],E[N];
  7.  float F1[N],F2[N];
  8.  FILE* fichero;
  9.  fichero = fopen("fecha0.txt", "r");
  10.  if ((fichero = fopen("fecha0.txt", "r")) == NULL){
  11.    perror("fecha0.txt");
  12.    return EXIT_FAILURE;
  13.  }
  14.  while (! feof(fichero)){
  15.      fscanf(fichero,"%d %d %d %d %f ", &aux[0],&aux[1], &aux[2], &E[i], &F1[i]);
  16.        printf("5: %d  %g\n", E[i], F1[i]);
  17.        i++;
  18.      fscanf(fichero,"%d %d %d %f ", &aux[0],&aux[1], &aux[2], &F2[k]);
  19.        printf("4: %g\n", F2[k]);
  20.        k++;
  21.  }
  22.  for (j=0;j<i;j++)
  23.    printf ("%3d  ",E[j]) ;
  24.  putchar ('\n');
  25.  for (j=0;j<i;j++)
  26.    printf ("%3g  ",F1[j]) ;
  27.  putchar ('\n');
  28.  for (j=0;j<k;j++)
  29.    printf ("%3g  ",F2[j]);
  30.  putchar ('\n');
  31.  fclose(fichero);
  32.  return EXIT_SUCCESS;
  33. }

Pero me sigue quedando la duda que planteé.
« Última modificación: 12 Marzo 2014, 20:43 pm por leosansan » En línea

rir3760


Desconectado Desconectado

Mensajes: 1.639


Ver Perfil
Re: Leer datos de un cierto formato desde un fichero
« Respuesta #3 en: 13 Marzo 2014, 03:20 am »

Me pasa un detalle para mi curioso. Con esto en el fichero:
Citar
...
1970-01-01 1.15
...
1980-01-01 1.225
...
1990-01-01 1.35

la salida es:
Citar
...
5: 1 0.15
...
5: 1 0.225
...
5: 1 0.35
Es decir, en el código que te pongo a continuación sólo actúa el scanf==5 y lo que hace el muy bandido es, cuando debería actuar para mi criterio el scanf==4, sigue actuando el scanf==5 y lo que hace es coger, en las líneas pares, el decimal y separarlo en la parte entera y la parte decimal y así no deja actuar al scanf==4.

¿Me podrían iluminar a ver qué diablos estoy haciendo fatal?.
El problema se debe a que la lectura con "%d %f" siempre sera exitosa ya se trate de un int y un float o bien un float.

Tomando como ejemplo la primera linea terminada con 1.15 el especificador "%d" consumirá "1" y "%f" consumirá ".15", eso explica la salida que obtienes en el programa.

Para solucionarlo hay que recordar que scanf y familia terminaran tan pronto falle una conversión, esa es la razón por la cual utilizo "%d%*[ ]%lf", ahí el espacio no es opcional, si no se encuentra por lo menos un espacio separando los dos números la función termina y su valor de retorno es uno.

Otro error en tu programa es, al utilizar directamente fscanf, el indicador de posición en el archivo se actualizara con la llamada a esa función sin importar su resultado.

Un saludo
En línea

C retains the basic philosophy that programmers know what they are doing; it only requires that they state their intentions explicitly.
--
Kernighan & Ritchie, The C programming language
javiepe

Desconectado Desconectado

Mensajes: 4


Ver Perfil
Re: Leer datos de un cierto formato desde un fichero
« Respuesta #4 en: 13 Marzo 2014, 10:43 am »

Muchas gracias a los dos, ya me va quedando todo más claro, pero todavía tengo una duda. Resulta que en el fichero que tengo, además de estas fechas con los números posteriores, hay una línea en la que pone "Observaciones" y otra en la que pone "Predicciones", y me está dando error al implementar vuestros programas. Más concretamente, no sé qué significan esos ==1, ==2.... que ponéis después de las funciones scanf, así que no sé cómo añadir el caso en el que una línea pueda ser  "Observaciones" o "Predicciones".

Además, también tengo dudas en cómo almacenar el fichero en el vector "linea" utilizando fgets para poder después procesarlo con sscanf.

Os agradezco de nuevo toda la ayuda, ya os digo que tengo bastante soltura en Fortran, pero que estoy bastante perdido en la forma de leer datos de C.
En línea

leosansan


Desconectado Desconectado

Mensajes: 1.314


Ver Perfil
Re: Leer datos de un cierto formato desde un fichero
« Respuesta #5 en: 13 Marzo 2014, 14:28 pm »

..............................................................................
no sé qué significan esos ==1, ==2.... que ponéis después de las funciones scanf,
........................................................................................

Representan el número de lecturas que "debe" realizar el sscanf para que este efectivamente haga la lectura. Está referido al número de %d y %f que hay en el sscanf.

..............................................................................
Además, también tengo dudas en cómo almacenar el fichero en el vector "linea" utilizando fgets para poder después procesarlo con sscanf.
........................................................................................


Por ejemplo:

Código
  1. ...........................................
  2. char linea[81];
  3. ............................................
  4. fgets(linea, 80, fichero);
  5. ........................................
  6.  

¡¡¡¡ Saluditos! ..... !!!!


« Última modificación: 13 Marzo 2014, 14:49 pm por leosansan » En línea

javiepe

Desconectado Desconectado

Mensajes: 4


Ver Perfil
Re: Leer datos de un cierto formato desde un fichero
« Respuesta #6 en: 13 Marzo 2014, 15:06 pm »

Gracias, ya me ha quedado claro lo de las lecturas del scanf.

Respecto a fgets aún hay un matiz que no me queda claro. En el ejemplo que pones, ¿se guarda el fichero por completo en "char linea"? Es decir, ¿linea(1) sería la primera línea del fichero, linea(2) la segunda, y así sucesivamente? Planteado de otra forma; ¿cuando hacemos fgets lee el fichero?

Saludos!
En línea

leosansan


Desconectado Desconectado

Mensajes: 1.314


Ver Perfil
Re: Leer datos de un cierto formato desde un fichero
« Respuesta #7 en: 13 Marzo 2014, 15:14 pm »

Gracias, ya me ha quedado claro lo de las lecturas del scanf.

Respecto a fgets aún hay un matiz que no me queda claro. En el ejemplo que pones, ¿se guarda el fichero por completo en "char linea"? Es decir, ¿linea(1) sería la primera línea del fichero, linea(2) la segunda, y así sucesivamente? Planteado de otra forma; ¿cuando hacemos fgets lee el fichero?

Saludos!

El caso que te pongo, con fgets después del while, leería línea a línea el fichero.

¡¡¡¡ Saluditos! ..... !!!!




En línea

javiepe

Desconectado Desconectado

Mensajes: 4


Ver Perfil
Re: Leer datos de un cierto formato desde un fichero
« Respuesta #8 en: 13 Marzo 2014, 15:33 pm »

Entendido! Ya me ha salido por fin! Os agradezco mucho a los dos vuestra ayuda, era muy importante que pudiese resolver esto para poder seguir.

Saludos!
En línea

Yoel Alejandro

Desconectado Desconectado

Mensajes: 254



Ver Perfil WWW
Re: Leer datos de un cierto formato desde un fichero
« Respuesta #9 en: 13 Marzo 2014, 18:58 pm »

Aunque ya está solucionado, sólo para mostrar una alternativa un poco bizarra pero que se reduce a un único sscanf(). La idea es leer ambos, el entero y el float como flotantes, y de ser necesario convertir el primero a entero. Lo probé y parece funcionar correctamente:

Código
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3.  
  4. int main(void)
  5. {
  6.   char *linea[] = {
  7.      "1970-01-01 1 2.3",
  8.      "1970-01-01 4.5",
  9.      "1980-01-01 1 2.3",
  10.      "1980-01-01 4.5",
  11.      "1990-01-01 1 2.3",
  12.      "1990-01-01 4.5",
  13.   };
  14.   size_t num_elem = sizeof linea / sizeof linea[0];
  15.   size_t i;
  16.  
  17.   unsigned a;
  18.   unsigned m;
  19.   unsigned d;
  20.   int num_ent;
  21.   double num_pf;
  22.  
  23.   int n_args;
  24.   float M, N;
  25.  
  26.   for (i = 0; i < num_elem; i++)
  27.      switch ( n_args = sscanf(linea[i], "%u-%u-%u %f%*[ ]%f", &a, &m, &d, &M, &N) ) {
  28.      case 5:
  29.         num_ent = (int)M;
  30.         num_pf = N;
  31.         printf("%u-%02u-%02u: %d, %.2f\n", a, m, d, num_ent, num_pf);
  32.         break;
  33.      case 4:
  34.         num_pf = M;
  35.         printf("%u-%02u-%02u: %.2f\n", a, m, d, num_pf);
  36.         break;
  37.      default:
  38.         puts("Error");
  39.      }
  40.  
  41.   return EXIT_SUCCESS;
  42. }
  43.  

Salida:

1970-01-01: 1, 2.30
1970-01-01: 4.50
1980-01-01: 1, 2.30
1980-01-01: 4.50
1990-01-01: 1, 2.30
1990-01-01: 4.50
En línea

Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)
Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

WAP2 - Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines