Mmmm, interesante
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:
#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:
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.