Leer valores numéricos de un fichero y almacenarlos en un array. C++.

Es un secreto a voces que hay lenguajes de programación más aptos a la hora de realizar ciertas tareas. Lo que nos ocupa hoy nos llevaría 3 o 4 líneas con Numpy (Python), en cambio con C++ veréis que es algo más largo.
En esta situación uno puede verse tentado a emplear algún truco para poder usar sus funciones favoritas en otros lenguajes, sin embargo dejarnos llevar por ello puede depararnos más complicaciones y quebraderos de cabeza que los que podemos tener si nos paramos a escribir un código en consonancia con el resto de nuestro proyecto. Pensad que si se escribe una vez, ya no deberá volver a escribirse.
Pensad también en otro problema de usar “trucos”; la portabilidad. Las librerías estándar no fallan, no necesitan opciones de compilación adicionales, etc.
Desconozco muchas cosas de este lenguaje y seguramente mi código será torpe y redundante, pero funciona y lo hace con las librerías estándar, que es lo que nos interesa a los que hacemos números (;
El problema es el siguiente, tenemos un fichero con datos que queremos guardar en un array y su formato es el siguiente:
# Time	Cd	Cl	Cm
1	-660.486	1.0285	-0.239618
2	-326.356	-1.86631	0.047646
3	166.242	-1.14998	0.0979555
4	235.177	0.835717	-0.0900095
25	-5.1296	0.303168	-0.191563
75	-5.11033	0.0031427	-2.12211e-05
76	-5.09629	0.00546416	-0.00169277
77	-5.09693	0.00482644	-0.0037029
Es el formato de salida de las funciones para calcular fuerzas sobre una superficie en OpenFOAM.
Como vemos tenemos notación científica y comentarios, hay que lidiar con ello.
El siguiente código hace tres cosas; cuenta las líneas no comentadas y las columnas de datos que hay en fichero y con ello dimensiona el array de datos, lee los datos como cadenas y los transforma a coma flotante, almacena los datos en el array.

/*
 * =====================================================================================
 *
 *       Filename:  readData.cpp
 *
 *    Description:  Programa para almacenar valores numericos tomados de un fichero
 *                  Soporta notacion cientifica (e-01) y lineas comentadas.
 *
 *        Version:  1.0
 *        Created:  10/01/13 10:57:22
 *       Revision:  0
 *       Compiler:  g++
 *
 *         Author:  Samuel Rodriguez Bernabeu (srodrb), srodrb@gmail.com
 *   Organization:  University of Leon (Spain)
 *
 * =====================================================================================
 */

#include <iostream>
#include <fstream>
#include <string>
#include <math.h>  // necesaria para pow
#include <cstdlib> // para atof en c++
using namespace std;

int main(int argc, const char *argv[])
{
//============================== Variables modificables por el usuario
string commentSymbol = "#";
const char* filename = "forceCoeffs/0/forceCoeffs.dat";
//============================== fin de las variables modificables por el usuario

string STRING;
string value;
string exp; //contiene el numero
int expValue = 0;
int numberOfLines = 0;
string previousLine="";
int numberOfValues = 1;

ifstream infile;
infile.open (filename);
if(!infile){printf("ERROR: cannot open %s\n", filename );}

// Contaremos las lineas que hay en el fichero, para poder reservar memoria adecuadamente
while(!infile.eof())
{
    getline(infile,STRING);

    if ((STRING != previousLine) && (STRING[0] != commentSymbol[0]))
    {
        numberOfLines++; // Contador del numero de lineas no comentadas

        if(numberOfLines == 1)
        {
            // Este bucle nos permite contar el numero de columnas que tiene el fichero.
            for (int i = 0; i < STRING.size()-1; i++) {
                // Mi formato solo tiene un espacio, de lo contrario modifica esta parte.
                if( isspace(STRING.at(i)) )
                {
                    numberOfValues++;
                }
            }
        }

        previousLine=STRING;
    }
}

numberOfLines--; // restamos uno porque no nos damos cuenta de que la linea esta repetida
                 // hasta despues de inicial el bucle de nuevo
infile.close();

float values[numberOfLines][numberOfValues];
int column = 0;
int row = 0;

infile.open (filename);
if(!infile){printf("ERROR: cannot open %s\n", filename );}

// Volvemos a abrir el fichero para empezar a leer desde cero.
while(!infile.eof())
{
    getline(infile,STRING);
    if (STRING != previousLine)
    {
        if( STRING[0] != commentSymbol[0] ) // filtramos las lineas comentadas
        {
            for (int i = 0; i < STRING.size(); i++) {

                if (!isspace(STRING.at(i))){

                    if(STRING.at(i) == 'e')
                    {
                        i++;
                        while( !isspace(STRING.at(i))) {
                            exp.append(STRING,i,1);
                            i++;
                            expValue = atoi(exp.c_str());
                            if(i == STRING.size()){goto endLoop;}
                        }
                    }

                    else{
                        value.append(STRING,i,1);
                        if(i==STRING.size()-1){goto endLoop;}
                    }
                }

                else{
                    endLoop:

                    values[row-1][column] =
                                     (double)strtod(value.c_str(),NULL)*
                                     (pow(10,expValue));
                    expValue = 0;
                    column++;
                    value.clear();
                    exp.clear();

                    }
            }
        }
        column = 0;
        row++;
    }
}

row = row-1; // Restamos 1 para no salirnos de la indexacion
             // el mismo problema de antes.
return 0;
}
Si mostramos el array tendremos la salida del programa:

1  -660.486  1.0285  -0.239618
2  -326.356  -1.86631  0.047646
3  166.242  -1.14998  0.0979555
4  235.177  0.835717  -0.0900095
25  -5.1296  0.303168  -0.191563
75  -5.11033  0.0031427  -2.12211e-05
76  -5.09629  0.00546416  -0.00169277
77  -5.09693  0.00482644  -0.0037029

Espero que le ahorre a alguien un rato escribiendo cosas que seguramente estarán en alguna librería que desconozco.
Si alguien usa el código y encuentra algún fallo no dude en escribirme. Por supuesto se aceptan mejoras, sugerencias, ect…
Esta entrada fue publicada en C/C++, OpenFOAM, Sin categoría y etiquetada , , . Guarda el enlace permanente.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s