Поскольку все вопросы CSV, похоже, перенаправляются сюда, я думал, что отправлю свой ответ здесь. Этот ответ напрямую не затрагивает вопрос афера. Я хотел иметь возможность читать в потоке, который, как известно, находится в формате CSV, а также типы каждого поля уже были известны. Конечно, приведенный ниже метод можно использовать для обработки каждого поля как строкового типа.
В качестве примера того, как я хотел использовать входной поток CSV, рассмотрим следующий ввод (взятый из страница wikipedia на CSV ):
const char input[] =
"Year,Make,Model,Description,Price\n"
"1997,Ford,E350,\"ac, abs, moon\",3000.00\n"
"1999,Chevy,\"Venture \"\"Extended Edition\"\"\",\"\",4900.00\n"
"1999,Chevy,\"Venture \"\"Extended Edition, Very Large\"\"\",\"\",5000.00\n"
"1996,Jeep,Grand Cherokee,\"MUST SELL!\n\
air, moon roof, loaded\",4799.00\n"
;
Затем я хотел иметь возможность читать данные следующим образом:
std::istringstream ss(input);
std::string title[5];
int year;
std::string make, model, desc;
float price;
csv_istream(ss)
>> title[0] >> title[1] >> title[2] >> title[3] >> title[4];
while (csv_istream(ss)
>> year >> make >> model >> desc >> price) {
//...do something with the record...
}
Это было решение, с которым я закончил.
struct csv_istream {
std::istream &is_;
csv_istream (std::istream &is) : is_(is) {}
void scan_ws () const {
while (is_.good()) {
int c = is_.peek();
if (c != ' ' && c != '\t') break;
is_.get();
}
}
void scan (std::string *s = 0) const {
std::string ws;
int c = is_.get();
if (is_.good()) {
do {
if (c == ',' || c == '\n') break;
if (s) {
ws += c;
if (c != ' ' && c != '\t') {
*s += ws;
ws.clear();
}
}
c = is_.get();
} while (is_.good());
if (is_.eof()) is_.clear();
}
}
template struct set_value {
void operator () (std::string in, T &v) const {
std::istringstream(in) >> v;
}
};
template struct set_value {
template void convert (std::string in, T &v) const {
if (SIGNED) v = ::strtoll(in.c_str(), 0, 0);
else v = ::strtoull(in.c_str(), 0, 0);
}
void operator () (std::string in, T &v) const {
convert::val>(in, v);
}
};
template const csv_istream & operator >> (T &v) const {
std::string tmp;
scan(&tmp);
set_value::val>()(tmp, v);
return *this;
}
const csv_istream & operator >> (std::string &v) const {
v.clear();
scan_ws();
if (is_.peek() != '"') scan(&v);
else {
std::string tmp;
is_.get();
std::getline(is_, tmp, '"');
while (is_.peek() == '"') {
v += tmp;
v += is_.get();
std::getline(is_, tmp, '"');
}
v += tmp;
scan();
}
return *this;
}
template
const csv_istream & operator >> (T &(*manip)(T &)) const {
is_ >> manip;
return *this;
}
operator bool () const { return !is_.fail(); }
};
С помощью следующих помощников, которые могут быть упрощены с помощью новых шаблонов интегральных признаков в C ++ 11:
template struct is_signed_int { enum { val = false }; };
template <> struct is_signed_int { enum { val = true}; };
template <> struct is_signed_int { enum { val = true}; };
template <> struct is_signed_int { enum { val = true}; };
template <> struct is_signed_int { enum { val = true}; };
template struct is_unsigned_int { enum { val = false }; };
template <> struct is_unsigned_int { enum { val = true}; };
template <> struct is_unsigned_int { enum { val = true}; };
template <> struct is_unsigned_int { enum { val = true}; };
template <> struct is_unsigned_int { enum { val = true}; };
template struct is_int {
enum { val = (is_signed_int::val || is_unsigned_int::val) };
};