Класс для работы с форматом CSV в строковых и файловых потоках и интерфейсом контейнера.

Класс CSVTrickster, использующий вариативные шаблоны, предназначен для чтения и парсинга данных в формате CSV и записи данных в этом же формате.
В качестве источников данных могут использоваться файловые и строковые потоки. Запись данных производится в потоки указанных типов по выбору клиентского кода.
Класс предоставляет интерфейс в соответствии с концепцией контейнера. Внутри класса контейнер реализован как вектор стандартной библиотеки, содержащий кортежи, соответствующие строкам CSV файла.

Далее описывается интерфейс класса CSVTrickster с примерами его использования.

1) Типы

using row_type = std::tuple<TList ...>;//тип "строки" во внутреннем контейнере

using row_type_ref = std::tuple<TList ...>&;////тип "строки" во внутреннем контейнере по ссылке

using iterator_type = typename std::vector<row_type>::iterator;//тип итератора "строк" внутреннего контейнера

using const_iterator_type = typename std::vector<row_type>::const_iterator;// константный тип итератора "строк" внутреннего контейнера

template<size_t ColumnNum>
using column_type = typename std::tuple_element<ColumnNum, row_type>::type;// тип "колонки" внутреннего контейнера, ColumnNum - номер "колонки".


2) Конструкторы, оператор присваивания и деструктор.

а) Конструктор предоставляет по умолчанию данные для инициализации всех полей настроек (описаны ниже);
Для избежания путаницы при использовании аргументов конструктора используются "строгие" типы, по методике, описанной здесь.
б) Конструкторы копирования и перемещения создают глубокие копии содержимого исходного объекта, его настроек и состояния входных и выходных потоков;
в) Оператор перемещения полностью замещает содержимое существующего объекта новым.
г) Деструктор закрывает файловые потоки.

using CSVT = CSVTrickster<string, int>;
CSVT trikster;//конструктор
CSVT trikster2(trikster);//конструктор копирования
CSVT* ptrikster = new CSVT(Separator(','));//конструктор с измененным первым аргументом
*ptrikster = trikster;//оператор присваивания
delete ptrikster;//деструктор

3) Настройки.

char separator_;
char quote_;
char escape_;
bool ignore_bad_row_length_;
bool skip_empty_lines_;
std::size_t skip_first_lines_;

Настройки парсинга и выходных данных могут быть как назначены в конструкторе, так и изменены в процессе работы вызовом одноименных методов, возвращающих ссылку.

CSVT trikster;//разделитель ';' (по умолчанию)
trikster.separator() = ',';//теперь разделитель - запятая

4) Работа с потоками производится вызовом следующих методов

std::size_t parse(const StringSource& s, std::size_t n = std::numeric_limits<std::size_t>::max());

CSVTrikster<string , int, string, string, string, string, string> reader;
reader.skip_first_lines() = 1;
std::string s = "CurrentTime;AreaID;CounterID;Time;Speed;Class;ClassComment";
s += '\n';
s += "24-1-2018 17:29:6;0;0;2018-01-24T17:29:06;151,787;2;(5.5-7 m)";
s += '\n';
reader.parse(StringSource(s));

std::size_t parse(const FileSource& file_name, std::size_t n = std::numeric_limits<std::size_t>::max());

CSVTrikster<string , int, string, string, string, string, string> reader;
reader.parse(FileSource("Data.csv"));

void write(StringSink s);

using CSVT = CSVTrickster<string, int>;
CSVT trikster;
trikster.separator() = ',';
trikster.push_back("Gala", 1966);
trikster.push_back("Sophia", 2007);
std::string ssink;
trikster.write(StringSink(ssink));


void write(const FileSink& file_name);



trikster.write(FileSink("Data.csv"));

Первые два метода производят чтение из файла или строки соответственно и парсинг данных. Вторые два записывают данные из внутреннего контейнера в строку или файл. Для перегрузки одноименных методов используются "строгие" типы, упомянутые выше.

5) Доступ к итераторам внутреннего контейнера

iterator_type begin();
iterator_type end();
const_iterator_type cbegin();
const_iterator_type cend();

using CSVT = CSVTrickster<string, int>;
CSVT trikster;
...............................
CSVT::iterator_type it;
for (it = trikster.begin();it!=trikster.end();it++)
{
if (std::get<0>(*it) == "Sophia")
break;
}

или так

for (auto e : trikster)
{
if (std::get<0>(e) == "Sophia")
break;
}

6) Доступ к "строкам" внутреннего контейнера по индексу

std::size_t rows() const;//размер вектора кортежей
row_type_ref operator[] (std::size_t i) ;//возврат кортежа из вектора по индексу
const row_type_ref operator[] (std::size_t i) const ;
row_type_ref at(std::size_t i) ;//возврат кортежа из вектора по индексу
const row_type_ref at(std::size_t i) const ;

Поведение функций в части генерации исключений при выходе индекса из диапазона аналогично одноименным методам std::vector.

7) Доступ к "колонкам" внутреннего контейнера

inline std::size_t columns() const;//число "колонок" = размер кортежa

template<typename ColumnType, std::size_t ColumnNumber>
std::vector<ColumnType> get_column();//получение вектора данных типа ColumnType "колонки" по индексу  ColumnNumber. Параметры задаются при компиляции.

using CSVT = CSVTrickster<string, int>;
CSVT trikster;
...............................
std::vector<int> v(trikster.get_column<int, 1>());


8) Добавление, удаление  "строк" , очистка внутреннего контейнера

template< class... Types >
void push_back(Types&&... args);

CSVTrickster<string, int> trikster;
trikster.push_back("Gala", 1966);

iterator_type insert(iterator_type it, row_type t);

CSVT::iterator_type it2 = trikster.insert(it, std::make_tuple("Alex", 1995));

iterator_type erase(iterator_type it);
iterator_type erase(iterator_type first, iterator_type last);

inline void clear();
inline  bool empty() const;

9) Операторы сравнения (члены класса) производят сравнение содержимого внутренних контейнеров (текущие настройки не учитываются).

bool operator==(const CSVTrickster<TList ...>& rhs);
bool operator!=(const CSVTrickster<TList ...>& rhs);

И последнее. Для использования пользовательских типов необходимо перегрузить для своего класса операторы operator>> и operator<< для входных и выходных потоков, например:


class TimeAsString
{
        string tas;
..........................................................
       //Some internal data
public:
friend istringstream &operator >>(istringstream &out, TimeAsString &t)
{
out >> t.tas;
//convert tas to some internal data
................................................................................................
return out;
}
friend std::ostream &operator << (std::ostream & out, const TimeAsString &t) 
        {
                //convert some internal data to tas
........................................................................................
return out << t.tas;
}

};


CSVTrickster<TimeAsString, int, float,std::string> trix;





Комментарии

Популярные сообщения из этого блога

Полезные новации С++17. Выражения свертки (Fold expressions)

Перегрузка и специализация шаблонных функций.

Поддержка декомпозиции при объявлении (structural bindings) для классов