miércoles, 29 de agosto de 2007

/fscanf errático o errática yo



Estoy desarrollando una algoritmo donde debo leer la información contenida en un archivo de texto, y con ella cargar un árbol con una cantidad no determinada de hijos. Justo en el dibujo quedó binario, pero no lo es. Los nodos del árbol tienen como información un nombre y un entero, y el formato del archivo de entrada es de este tipo: (A 1 (B 4 (C 3)) (D 7))
Cada nodo se representa por el par (nombre número).

Nota: no importa lo que haya entre dos paréntesis iguales )) puede haber cualquier cosa, si la entrada fuera (A 1 (B 4 (C 3)au) (D 7)111), el resultado sería el mismo.

Es obvio que la lectura es una función recursiva, y decidí hacerla empleando fscanf (o man fscanf para mas información) porque me permite chequear expresiones.


Al principio buscaba por fscanf(f,"%[()]",&c) donde c es un char. La idea era buscar por el carácter que sea "(" o ")" y leerlo, luego chequear cual fue leído.
El pseudocódigo, después postearé la solución, sería algo asi:


if c == "("
{
leo numero y nombre
creo nodo
llamo con hijo (nodo)
llamo con hermano del padre de nodo
asigno padre al hijo.
}


El problema con
fscanf(f,"%[()]",&c) es que para leer un carácter segun entiendo no saltea blancos, tabuladores, nueva línea, etc, y si bien identificaba bien los caracteres, la lectura de los datos posteriores (nombre y número) era errática. Por ejemplo a veces incluía el "(" al nombre, o sea quedaría algo asi como (B, y en otras no. No era en todos los casos.

La forma que encontré para solucionarlo fue usar lo siguiente:

char* lin; fscanf(f,"%[^()]",lin); (1)
fscanf(f,"%c",&c); (2) // leo el paréntesis que corresponda
fscanf(f,"%20s%d",nom,nro); // leo los datos del nodo

Lo que hace (1) es leer, saltando blanco, tabuladores, etc, todo hasta que encuentre alguno de los caracteres "(" o ")", esos no los lee. Para leer
los uso (2).
El string lee hasta el primer blanco, nueva línea o tabulador.

La estructura elegida para el árbol es la siguiente (las listas entre hermanos son doblemente encadenadas, algunos requerimientos asi lo imponen) :

Aclaro que omití el puntero al padre de cada nodo por motivos de claridad, pero basta ver cuales son los hijos de cada nodo para notar a qué nodo padre apuntan.

Traducido a C:

struct Arbol
{
int numero;
int cantHijos;
char* nombre;
struct Arbol* hijos;
struct Arbol *herSig,*herAnt;
struct Arbol* padre;
};


Disculpen los dibujos, pero espero sean claros, y como siempre cualquier sugerencia o mejora es bienvenida. Tampoco se si esta será mi solución definitiva.









2 comentarios:

nachokhan dijo...

hola rochi! muy interesante lo que planteás. Te cuento que yo jamás uso fscanf() para leer archivos por ese motivo; como no sé bien como funciona, a veces hace cosas que no quiero; o no hace las que sí quiero. ;)

En cambo, uso fgetc(); o incluso si vale la pena, creo mi propia función leer() bien específica.

Te cuento q empecé un posgrado de modelación científica (esta excelente!!! :) y ando con re-poco tiempo. Pero me interesaría tratar de ayudarte. Espero poder
Un beso, nos vemos! suerte!

rog dijo...

hola nacho!, sí la info que encontré sobre fscanf nunca fue demasiado ilustrativa, al menos para mi (mejor aclaro). Su funcionalidad la aprendo viendo otros códigos. En principio me pareció mas adecuada para leer expresiones de acuerdo a un patrón. Con fgetc() como que debo andar armando mi string y me pareció que me complicaba.

Modelación científica, imagino por donde va..pinta interesante, buenísimo colgarse con lo que a uno le toca estudiar. Si tenes algun link de la cátedra..thanks

No te preocupes por el tiempo, estoy igual, te escribo por un material pendiente...
bechus...nos vemos