c ++ чтение форматированных табличных данных из файла с использованием BOOST / STL / etc - PullRequest
3 голосов
/ 24 февраля 2011

Каков наилучший способ для меня создать функцию чтения / записи форматированных данных для табличного текстового файла. Скажи несколько звонков, как:

readElement(i,j)

insertRow(elem[])

readColHeaders()

Мне было интересно, может ли какая-либо существующая обертка сделать это?

внутренний формат - данные с табуляцией или ИЛИ CSV.

Thnx-Эгон

Ответы [ 4 ]

3 голосов
/ 24 февраля 2011

Есть много читателей csv, но я никогда не находил ничего хорошего.

Самое простое - использовать boost :: tokenize для заполнения вектораиз вашего файла.Более причудливый способ - использовать boost :: spirit (но кривая обучения - американские горки).

Для генерации файла, итерации по векторудовольно тривиально.

1 голос
/ 24 февраля 2011

Чтобы прочитать таблицу с разделителями табуляцией в вектор строковых векторов ...

#include <vector>
#include <string>
#include <sstream>
#include <iostream>

typedef std::vector<std::string> StringVec;
typedef std::vector<StringVec> RowVec;

RowVec readRows(std::istream& f) {
    std::string line;
    RowVec rows;
    while (std::getline(f, line)) {
        rows.push_back(StringVec());
        std::string entry;
        std::istringstream linestrm(line);
        while (std::getline(linestrm, entry, '\t')) {
            rows.back().push_back(entry);
        }
    }
    return rows;
}

int main() {
    std::istringstream textFile("a\tb\tc\n1\t2\t3");
    RowVec rows = readRows(textFile);
    std::cout << rows.size() << std::endl;
    std::cout << rows[0][0] << std::endl;
    std::cout << rows[1][2] << std::endl;
    return 0;
}
1 голос
/ 24 февраля 2011

Не существует "стандартного" csv-ридера / писателя для C или C ++.Это не значит, что вы не можете найти какой-то существующий библиотечный код для использования, но нет единой библиотеки, которая бы управляла ими всеми.В моей работе мы интенсивно используем CSV-файлы, поэтому я пошел дальше и развернул свои собственные, чтобы максимально соответствовать моему рабочему процессу.Я могу рассказать вам о некоторых вещах, которые я сделал в моей библиотеке, которые сработали достаточно хорошо, если вы захотите сделать также и свою собственную вещь:

  • Я храню данные каквектор векторов наддува :: любой.Я позволил пользователю указать формат данных в конструкторе, аналогично тому, как вы передаете формат в scanf.Это удерживает пользователя от необходимости делать свои собственные приведения.Я использую boost :: tokenize и boost :: lexical_cast для фактического разделения и приведения.Это, очевидно, не будет работать хорошо, если ваши CSV-файлы не помещаются в памяти, но это редко проблема для меня.

  • У меня может быть шаблонный get (), который выполняетany_cast и возвращает правильные данные.

  • У меня есть хэш имен столбцов для их индекса, чтобы поддерживать поиск по имени столбца, а не просто поиск по позиции

  • IПозволяет пользователю указать «первичный ключ» некоторой комбинации столбцов, а затем сохранить хэш, чтобы для каждой строки было сопоставление значений в ключе -> номер строки.Например, если вы читаете данные по акциям, вы можете захотеть найти строку, основанную на CUSIP или тикере, а не вводить целые данные, чтобы найти вашу строку.

  • Позвольте пользователю указать подсказку о размере, чтобы вы могли зарезервировать () в вашем хранилище

  • Позвольте пользователю указать функции обратного вызова, чтобы он могобрабатывать и фильтровать строки, которые ему не нужны, когда вы читаете / пишете их

  • Разрешить пользователю указывать, нужно ли блокировать файл при чтении / записи

  • Разрешить пользователю передавать свой собственный заголовок столбца для файлов, которые не имеют заголовка в файле

Не вступать в языковую дискуссию, но эта библиотека былана самом деле это порт чего-то, что я изначально делал в perl, и, черт побери, если не было в 10 раз проще писать и в 10 раз удобнее использовать в perl.Я не рекомендую делать CSV-обработку в C ++, если вы можете помочь.

0 голосов
/ 24 февраля 2011

Если ваши данные маленькие (например, менее нескольких сотен мегабайт), я бы прочитал весь файл в память. Для этого вы можете сохранить его в строковой матрице, такой как boost::numeric::ublas::matrix<std::string>, или в векторе, например, std::vector<std::vector<std::string> >

.

Boost.Spirit дает очень хороший способ разбить этот тип текстовых данных на эти структуры. Это сводится к команде разбора, как:

boost::spirit::qi::phrase_parse(
    begin,
    end, 
    // parse rule:

        *(char_ - '\t') % '\t' 

    // end parse rule
    space,
    vec);`

Больше примеров спиртных напитков здесь: http://www.boost.org/doc/libs/1_46_0/libs/spirit/doc/html/spirit/qi/tutorials.html

...