Consulta ficheros

Iniciado por Godor, 19 Diciembre 2014, 11:13 AM

0 Miembros y 1 Visitante están viendo este tema.

Godor

Hola amigos, tengo la siguiente duda respecto a un fichero.

El fichero tiene el formato (coordenada x,coordenada y)(coordenada x, coordenada y)---(coordenada x,coordenada y)(coordenada x, coordenada y)---(coordenada x,coordenada y)(coordenada x, coordenada y)

Así sucesivamente.

Mi idea es guardar en una estructura las coordenadas x1, y1, x2, y2, todas en 4 variables distintas, se como hacer para separar en la linea por el patron "---", pero no sé como guardar en las estructuras como numeros, lo que me quedara (coordenadax, coordenaday)(coordenada x, coordenada y), una vez separado.

Alguna ayudita porfa

eferion

divide y vencerás. Sabes separar por el primer grupo "---". Presupongo que al "separar", lo elementos que hacen las veces de "separador" se eliminan entonces:

* Coges cada subgrupo y separas por "(". Tras esto te quedan tres subgrupos nuevos: uno vacío y dos con el contenido"coordx,coordy)" y "coordx,coordy)".

* Omites el primer subgrupo, y para los dos restantes, eliminas el último carácter de cada uno.

* Ahora separas cada uno de estos últimos subgrupos por "," y ya tienes "coordx" y "coordy" correctamente separadas.

Es una forma de actuar. Otra forma puede ser:

* Recorres la cadena aplicando las siguientes reglas:

1. Si te encuentras "(", entonces es que lo siguiente que viene es la coordenada x
2. Si encuentras ",", has terminado de leer la coordenada x y lo siguiente es la coordenada y
3. Si encuentras ")", has terminado de leer la coordenada y. Si es la primera vez que encuentras este carácter vuelves a repetir el proceso para leer las siguientes coordenadas.

Orubatosu

Si la pregunta es "para guardar en un fichero", te diría que simplemente lo separaras con espacios y lineas

Por ejemplo:

22.5 13.22 11.55 -52.22
13.5 11.13 -9.5 6.33
.
.
.
.
etc...

Simple y fácil, sobre todo porque a la hora de leer el fichero puedes pillar los numeros directamente sin complicarte la vida con separadores de ningún tipo

"When People called me freak, i close my eyes and laughed, because they are blinded to happiness"
Hideto Matsumoto 1964-1998

Yoel Alejandro

#3
Mmmm, interesante  :rolleyes:

Bueno desde mi punto de vista, interpretar el fichero de texto formateado como dices es como hacer un mini-análisis léxico. Es decir, tienes que distinguir los "tokens" o palabras clave en que se divide tu archivo. Los tokens serían por ejemplo:


  • el carácter '('
  • el carácter ')'
  • el carácter ','
  • la secuencia de caracteres "---"
  • los números, o cadenas conformadas por dígitos consecutivos cada uno comprendido entre el 0 y el 9

Cualquier carácter o cadena de caracteres que no encaje en uno de estos patrones sería una palabra no reconocida. Pues bien, tu programa debe leer el fichero de texto de principio a fin, y desglosarlo en los posibles tokens reconocidos.

Voy a suponer que cada posible token tiene una longitud máxima de 50 caracteres, por ello la representamos por medio de un array de 51 caracteres (incluyendo el nulo de terminación). Si esto no es así hay opciones como arreglos dinámicos (función realloc(), o la clase string de C++), pero no se si esto sería muy avanzado para que lo pruebes en este momento)

Supongamos que tienes un fichero llamado datos.txt con el contenido:

(1,2)(3,4)---(10,6)(7,18)


Entonces el siguiente programa lee el fichero y lo desglosa en tokens:
Código (cpp) [Seleccionar]

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int extract_token( FILE *, char * );
int isInt( const char * );

int main( ) {

char *file = "datos.txt";
char token[51];
FILE *fPtr;

/* Definiendo la estructura COORD, con capacidad para diez números */
struct COORD {
int x1[10];
int y1[10];
int x2[10];
int y2[10];
};
struct COORD P; /* objeto de tipo struct COORD */
int count = 0; /* lleva el conteo de miembros en COORD */

if ( ( fPtr = fopen(file, "r") ) == NULL )
return -1; /* error al abrir el fichero */

int status;
while ( !feof(fPtr) && !ferror(fPtr) ) {
*token = '\0'; /* inicializa cadena vacía */
extract_token( fPtr, token );
printf( "token: %s\n", token );
}

fclose( fPtr );
return 0;
}

/* Extrae un token del fichero.
* Devuelve 1 si finalizó el archivo o si reconoció un token valido.
* En cualquier otro caso, devuelve cero.
*/
int extract_token( FILE *fPtr, char *token )  {

char c;
size_t len;

while ( ( c = fgetc( fPtr ) ) != EOF ) {

//printf( "c: %c,\ttoken: %s\n", c, token );
/* ignorar espacios */
if ( isspace( c ) ) continue;

/* encontró parentesis, token reconocido y finalizar */
if ( *token == '\0' && c == '(' ) {
strcpy( token, "(" );
return 1;
}
/* encontró parentesis, token reconocido y finalizar */
if ( *token == '\0' && c == ')' ) {
strcpy( token, ")" );
return 1;
}
/* encontró coma, token reconocido y finalizar */
if ( *token == '\0' && c == ',' ) {
strcpy( token, "," );
return 1;
}
/* encontró '-' añadir al token, pero al haber tres '-' seguidos,
* finalizar */
if ( c == '-' ) {
strcat( token, "-" );
if ( !strcmp( token, "---" ) ) return 1;
continue;
}
/* encontró el primer carácter numérico, añadir a la cadena y continuar */
if ( *token == '\0' && isdigit(c) ) {
token[0] = c;
token[1] = '\0';
continue;
}
/* si token es una cadena numérica ... */
if ( isInt( token ) ) {
/* ... y se haya un nuevo carácter, añadir */
if ( isdigit( c ) ) {
len = strlen( token );
token[len] = c;
token[len + 1] = '\0';
}
/* ... sino, terminar */
else {
ungetc( c, fPtr ); /* "devuelve" el caracter al archivo */
return 1;
}
}

/* si es carácter no reconocido, terminar */
if ( !isspace(c) && !isdigit(c) && c != ',' && c != '(' && c != ')' && c != '-' )
return 0;
}

return 0;
}

/* Decide si la cadena corresponde a un numero entero */
int isInt( const char *s ) {

char *cPtr = (char *)s;

if ( *cPtr == '\0' ) return 0; /* devuelve 0 si la cadena es nula */

while ( *cPtr != '\0' ) {
if ( !isdigit( *cPtr ) ) return 0;
cPtr++;
}
return 1;
}


Observa la salida:

token: (
token: 1
token: ,
token: 2
token: )
token: (
token: 3
token: ,
token: 4
token: )
token: ---
token: (
token: 10
token: ,
token: 6
token: )
token: (
token: 7
token: ,
token: 18
token: )
token:

o sea, que ha identificado los tokens: "(", "1", ",", ... etc

Luego de esto ya tienes divivido el fichero, lo que viene es más fácil. Sólo tienes que agarrar los tokens e irlos asignando como valores de x1, y1, x2, y2.

/*************************************************************************************/
(Continuando el tema)

Voy a asumir que vas a leer como máximo 10 cuartetas de valores (por supuesto, puedes indicar una cantidad mayor, o si lo prefieres, programar arrays dinámicos que crezcan conforme la necesidad, pero esto es más avanzado)
En fin, modifica el código de la función main() de la siguiente manera:

Código (cpp) [Seleccionar]

int main( ) {

char *file = "datos.txt";
char token[51];
FILE *fPtr;

/* Definiendo la estructura COORD, con capacidad para diez números */
#define MAX 10 /* <-- asignas el tamano maximo de cuartetos a leer */
struct COORD {
int x1[MAX];
int y1[MAX];
int x2[MAX];
int y2[MAX];
};
struct COORD P; /* objeto de tipo struct COORD */
int count = 0; /* lleva el conteo de miembros en COORD */
int i, k = 0;

if ( ( fPtr = fopen(file, "r") ) == NULL )
return -1; /* error al abrir el fichero */

while ( !feof(fPtr) && !ferror(fPtr) ) {
*token = '\0'; /* inicializa cadena vacía */
extract_token( fPtr, token );
//printf( "token: %s\n", token );

if ( isInt(token) && count < MAX) {
switch ( k % 4 ) {
case 0:
P.x1[count] = atoi(token);
break;
case 1:
P.y1[count] = atoi(token);
break;
case 2:
P.x2[count] = atoi(token);
break;
case 3:
P.y2[count] = atoi(token);
count++;
break;
}
k++;
}
}
printf( "x1\ty1\tx2\ty2\n----------------------------\n" );
for ( i = 0; i < count; i++ )
printf( "%d\t%d\t%d\t%d\n", P.x1[i], P.y1[i], P.x2[i], P.y2[i] );

fclose( fPtr );
return 0;
}


La variable "count" lleva el conteo de los cuartetos leidos, que debe ser menor a la constante definida MAX. La variable auxiliar k se utiliza para leer consecutivamente x1, luego y1, luego x2, luego y2. En efecto, aumentamos consecutivamente el valor de k y luego calculamos su resto de la división entera entre 4, el cual puede ser 0, 1, 2 ó 3, es como un contador cíclico que se reinicia continuamente.

La salida del anterior programa, es como se muestra:


x1   y1   x2   y2
----------------------------
1    2   3    4
10   6   7   18


Puedes probar modificando el fichero datos.txt y observando los resultados. Por supuesto, si dicho fichero está escrito de manera incorrecta, los valores obtenidos por el programa no serán correctos, y además no hemos programado rutinas para verificación y validación de datos (aunque sería deseable hacerlo).

Estoy a tu disposición si quieres mejorar, ampliar o corregir esta propuesta, o adaptarla mejor a lo que necesitas ....
Yoel.
Saludos, Yoel.
P.D..-   Para mayores dudas, puedes enviarme un mensaje personal (M.P.)