Skip to content

Instantly share code, notes, and snippets.

@hmito
Last active December 23, 2015 15:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hmito/dafa0575aca71385668e to your computer and use it in GitHub Desktop.
Save hmito/dafa0575aca71385668e to your computer and use it in GitHub Desktop.
[C++] csvファイル入出力用のiteratorを作ってみた話 ref: http://qiita.com/hmito/items/45289b60e5274796b52b
#include <iostream>
#include <fstream>
#include "csv_iterator.hpp"
int main(){
//カンマ区切り(csv)でファイルを読みだして、タブ区切りで画面に出力する
auto oitr = csv::current(std::cout, csv::mode::tsv);
std::ifstream fin("data.csv");
for(auto itr = csv::begin(fin, csv::mode::csv); itr != csv::end(fin); ++itr){
*oitr++ = *itr;
if(itr.eol())oitr.endl();
}
system("pause");
return 0;
}
std::vector<std::string> StringSet = {"Red", "Blue", "Green", ...};
std::ofstream fout("test.csv");
auto oitr = csv::begin(fout);
//StringSet配列内の文字列を順に出力
for(auto Str: StringSet){
*oitr = Str;
++oitr; //次のフィールドへ
}
//改行はendlメンバ関数
oitr.endl();
#include <iostream>
#include <fstream>
#include "csv_iterator.hpp"
int main(){
std::ifstream fin("data2.csv");
auto itr = csv::begin(fin, csv::mode::csv);
//1行読み飛ばす
csv::advance_line(itr);
//名前、性別、年齢の順で読みだす
while(itr != csv::end(fin)){
unsigned int Num;
(*itr++) >> Num;
for(unsigned int Cnt = 0; Cnt < Num; ++Cnt){
std::cout << "[" << Cnt << "/" << Num << "]" << (*itr++) <<std::endl;
}
}
system("pause");
return 0;
}
template<class Elem = char, class Traits = std::char_traits<Elem> >
class basic_ocsv_iterator : public std::iterator < std::output_iterator_tag, void, void, void, void >{
private:
using my_type = basic_ocsv_iterator < Elem, Traits >;
using ostream_type = std::basic_ostream < Elem, Traits >;
using string_type = std::basic_string < Elem, Traits >;
using csv_mode_type = basic_csv_mode<Elem, Traits>;
private:
struct output_cell;
private:
ostream_type* pstream;
csv_mode_type CSVMode;
bool IsCellHead;
bool IsLineHead;
public:
basic_ocsv_iterator()
: pstream(nullptr){}
basic_ocsv_iterator(ostream_type& Stream_, csv_mode_type CSVMode_)
: pstream(&Stream_)
, CSVMode(CSVMode_)
, IsCellHead(false)
, IsLineHead(true){}
basic_ocsv_iterator(const my_type& My_) = default;
my_type& operator=(const my_type& My_) = default;
public:
operator bool()const{ return pstream; }
output_cell operator*(){ return output_cell(*this); }
my_type& operator++(){
IsCellHead = true;
IsLineHead = false;
return *this;
}
my_type operator++(int){
my_type ans(*this);
operator++();
return ans;
}
bool eol()const{ return IsLineHead; }
void endl(){
(*pstream) << CSVMode.End;
IsLineHead = true;
IsCellHead = false;
}
};
struct output_cell{
private:
my_type& My;
private:
void cell_head_treat(){
if(My.IsCellHead && !My.IsLineHead){
*(My.pstream) << My.CSVMode.Sep;
}
My.IsCellHead = false;
}
public:
output_cell(my_type& My_) :My(My_){}
void operator=(const string_type& Str){
cell_head_treat();
//エスケープ文字周りの処理
*(My.pstream) << csv::cell_encode(Str, My.CSVMode);
}
template<typename T>
output_cell& operator<<(const T& Val){
cell_head_treat();
*(My.pstream) << Val;
return *this;
}
friend std::basic_istream<Elem, Traits>& operator>>(std::basic_istream<Elem, Traits>& in, output_cell p){
string_type Str;
in >> Str;
p = Str;
return in;
}
};
std::ofstream fout("test.csv");
auto oitr = csv::begin(fout);
(*oitr++)<<32;
(*oitr++)<<35;
(*oitr++)<<40;
//出力:32,35,40
std::ifstream fin("data.csv");
int Cell=0;
int Line=0;
for( auto itr = csv::begin(fin); itr!= csv::end(fin); ++itr){
std::cout<<"["<<Line<<","<<Cell<<"]: "<<*itr;
if(itr.eol()){
Cell=0;
Line++;
}else{
Cell++;
}
}
template<class Elem = char, class Traits = std::char_traits<Elem> >
class basic_icsv_iterator : public std::iterator < std::input_iterator_tag, std::basic_string<Elem, Traits>>{
private:
using my_type = basic_icsv_iterator < Elem, Traits >;
public:
using sstream_type = std::basic_stringstream < Elem, Traits >;
using istream_type = std::basic_istream < Elem, Traits >;
using pos_type = typename istream_type::pos_type;
using string_type = std::basic_string < Elem, Traits >;
using csv_mode_type = basic_csv_mode<Elem, Traits>;
private:
istream_type* pstream;
csv_mode_type CSVMode;
pos_type Pos;
sstream_type sstream;
bool HasRead;
pos_type ReadPos;
bool IsLineHead;
private:
//次のフィールドまでistreamの読み込み位置を進める
void next(){
if(HasRead){
HasRead = false;
Pos = ReadPos;
} else{
Elem c;
pstream->seekg(0, std::ios::end);
auto EndPos = pstream->tellg();
pstream->seekg(Pos);
bool EscFlag = false;
while(pstream->tellg() != EndPos){
c = pstream->get();
if(c == CSVMode.End || c == EOF){
IsLineHead = true;
break;
}
if(c == CSVMode.Sep && !EscFlag){
IsLineHead = false;
break;
}
if(c == CSVMode.Esc){
EscFlag = !EscFlag;
}
}
Pos = pstream->tellg();
}
}
//次のフィールドの内容を読み込む
sstream_type& read(){
if(!HasRead){
Elem c;
sstream.str(string_type());
sstream.clear();
pstream->seekg(0, std::ios::end);
auto EndPos = pstream->tellg();
pstream->seekg(Pos);
bool EscFlag = false;
while(pstream->tellg() != EndPos){
c = pstream->get();
if(c == CSVMode.End || c == EOF){
IsLineHead = true;
break;
}
if(c == CSVMode.Sep && !EscFlag){
IsLineHead = false;
break;
}
if(c == CSVMode.Esc){
EscFlag = !EscFlag;
}
sstream << c;
}
ReadPos = pstream->tellg();
HasRead = true;
}
return sstream;
}
private:
struct input_cell;
public:
basic_icsv_iterator() :pstream(nullptr){}
basic_icsv_iterator(istream_type& Stream_, pos_type Pos_, csv_mode_type CSVMode_, bool IsLineHead_)
: pstream(&Stream_)
, CSVMode(CSVMode_)
, Pos(Pos_)
, sstream()
, HasRead(false)
, IsLineHead(IsLineHead_){}
input_cell operator*(){ return input_cell(*this); }
my_type& operator++(){
next();
return *this;
}
my_type operator++(int){
basic_icsv_iterator ans(*this);
operator++();
return ans;
}
bool eol()const{ return IsLineHead; }
bool eof(){
pstream->seekg(0, std::ios::end);
return Pos == pstream->tellg();
}
friend bool operator==(const my_type& my1, const my_type& my2){
if(&my1 == &my2)return true;
if(my1.pstream != my2.pstream) return false;
return my1.Pos == my2.Pos;
}
friend bool operator!=(const my_type& my1, const my_type& my2){ return !(my1 == my2); }
};
struct input_cell{
private:
my_type& My;
public:
input_cell(my_type& My_) :My(My_){}
operator string_type(){ return csv::cell_decode(My.read().str(), My.CSVMode); }
template<typename T>
input_cell& operator>>(T& Val){
My.read() >> Val;
return *this;
}
friend std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& out, input_cell p){
return out << static_cast<string_type>(p);
}
friend bool operator==(const input_cell& in, const string_type& str){return in.raw_str() == str;}
friend bool operator!=(const input_cell& in, const string_type& str){ return in.raw_str() != str; }
};
std::ifstream fin("data.csv");
auto itr = csv::begin(fin);
double a;
int b;
//doubleで読み込み
(*itr++)>>a;
//intで読み込み
(*itr++)>>b;
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include "csv_iterator.hpp"
int main(){
std::vector<std::string> Names;
std::vector<bool> IsFemales;
std::vector<int> Ages;
std::ifstream fin("data.csv");
auto itr = csv::begin(fin, csv::mode::csv);
//1行読み飛ばす
csv::advance_line(itr);
//名前、性別、年齢の順で読みだす
while(itr != csv::end(fin)){
//文字列なら直接読み出し可能
Names.push_back(*itr++);
if(itr.eol())continue;
//当然、文字列との比較も可能
IsFemales.push_back(*itr++ == "F");
if(itr.eol())continue;
//型を指定して読み出すことも可能
Ages.push_back((*itr++).read<int>());
}
std::cout << "=name=" << std::endl;
for(const auto& val : Names)std::cout << val << std::endl;
std::cout << std::endl;
std::cout << "=sex=" << std::endl;
for(auto val : IsFemales)std::cout << val << std::endl;
std::cout << std::endl;
std::cout << "=age=" << std::endl;
for(auto val : Ages)std::cout << val << std::endl;
std::cout << std::endl;
system("pause");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment