Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Visual C++/MFC/WTL > Считывание численных данных из txt файла


Автор: chaoss 27.8.2009, 20:09
Имеется текстовый файл (.txt), в котором записаны табличные численные данные. Данные разделены внутри строки tab-ми и, соответственно переходом на новую строку. Данные могут быть как целыми, так и дробями (разделяемые точкой или запятой, не суть важно).
Нужно, чтобы программа, написанная на Visual C++, могла взять такой txt файл и считать от туда все численные данные.

Проблема заключается в том, что надо во-первых в тексте распознать сами эти числа, а затем правильно их прочитать, учитывая все тонкости с дробями и т.п.

Решая эту проблему, я написал некоторый алгоритм, но, честно говоря, его работой не очень доволен. Работает, но приходится представлять данные в другом виде, более удобном для программы, но не удобном для чтения, встречаются неприятные исключения, одним словом, криво работает.

Наверняка, у такой распространенной задачи существует на много более простое решение. Буду благодарен за помощь. smile

Автор: andrew_121 28.8.2009, 00:30
Наверное правильней было бы вопрос тут задать: http://forum.vingrad.ru/forum/forum-471.html

Вот. Работает.
Код

#include <string>
#include <vector>
#include <fstream>
#include <iostream>

typedef std::vector<std::string> line_type;
typedef std::vector<line_type> table_type;

/***************************************************************************/

line_type split(const std::string& str, std::string::value_type c) {
    line_type final;
    int j = 0;
    int i = str.find(c, j);
    int l = str.length();

    while ( i != -1 ) {
        if ( i > j && i <= l )
            final.push_back(str.substr(j, i - j));
        j = i + 1;
        i = str.find(c, j);
    }

    if ( str.substr(j, l-j+1).length() > 0 )
        final.push_back(str.substr(j, l-j+1));

    return final;
}

int main(int argc, const char** argv) {
    std::string temp;
    line_type line;
    table_type table;
    
    std::ifstream file("file.txt");
    if ( !file ) return 1;
    
    while ( !file.eof() ) {
        std::getline(file, temp);
        if ( temp.empty() ) continue;
        line = split(temp, '\t');
        table.push_back(line);
    }
    
    /** выводим в консоль */
    table_type::iterator str_it = table.begin();
    for ( ; str_it != table.end(); str_it++ ) {
        line_type::iterator line_it = str_it->begin();
        for ( ; line_it != str_it->end(); line_it++ ) {
            std::cout << *line_it << " ";
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;
    
    return 0;
}

/***************************************************************************/


Автор: andrew_121 28.8.2009, 02:51
Немного поразмыслив, дополнил первый вариант классом variant
Это позволит приводить хранимые в файле значения, к нескольким типам, таким как: int, long long(тобишь __int64), double, std::string
Код

#include <string>
#include <vector>
#include <fstream>
#include <iostream>

class variant;

typedef std::vector<variant> line_type;
typedef std::vector<line_type> table_type;

/***************************************************************************/

class variant {
public:
    variant(const std::string& s):str(s) {}
    variant(const variant& v):str(v.str) {}
    ~variant() {}
    /**  */
    int             to_int()        const { return atoi(str.c_str()); }
    double      to_double() const { return (double)atof(str.c_str()); }
    long long   to_int64()    const { return (long long)atof(str.c_str()); }
    std::string to_string()   const { return str; }
    /**  */
    operator int()                const { return atoi(str.c_str()); }
    operator std::string()    const { return str; }
private:
    variant();
    std::string str;
};

/***************************************************************************/

line_type split(const std::string& str, std::string::value_type c) {
    line_type final;
    int j = 0;
    int i = str.find(c);
    int l = str.length();

    while ( i != std::string::npos ) {
        if ( i > j && i <= l )
            final.push_back(str.substr(j, i - j));
        j = i + 1;
        i = str.find(c, j);
    }

    if ( str.substr(j, l-j+1).length() > 0 )
        final.push_back(str.substr(j, l-j+1));

    return final;
}

int main(int argc, const char** argv) {
    std::string temp;
    line_type line;
    table_type table;
    
    std::ifstream file("file.txt");
    if ( !file ) return 1;
    
    while ( !file.eof() ) {
        std::getline(file, temp);
        if ( temp.empty() ) continue;
        line = split(temp, '\t');
        table.push_back(line);
    }
    
    int iv = table[0][1].to_int();
    double dv = table[0][5].to_double();
    
    /** выводим в консоль */
    table_type::iterator str_it = table.begin();
    for ( ; str_it != table.end(); str_it++ ) {
        line_type::iterator line_it = str_it->begin();
        for ( ; line_it != str_it->end(); line_it++ ) {
            std::cout << *line_it << " ";
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;
    
    return 0;
}

/***************************************************************************/


Добавлено @ 02:52
Вот файл на котором тестировал:
Код

1    2    34    65    2.12    4.3
9.01    32.71    4    6    76    91


Добавлено @ 02:53
Как и требовалось, значения разделены табом('\t')

Автор: chaoss 28.8.2009, 03:24
Большое спасибо!
Буду разбираться с кодом и вставлять в свою программу.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)