Created
August 10, 2018 05:01
-
-
Save lichray/400875699c490eed11000861472ccb1e to your computer and use it in GitHub Desktop.
A tiny CSV data reader for online coding tests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <algorithm> | |
#include <assert.h> | |
#include <cmath> | |
#include <errno.h> | |
#include <iterator> | |
#include <stdlib.h> | |
namespace csv | |
{ | |
using std::begin; | |
using std::end; | |
template <char c, class It> | |
It next_maybe(It it, It last) | |
{ | |
if (c != ',' and it == last) | |
return it; | |
else | |
return std::next(it); | |
} | |
template <class It, class OutIt, class Pred> | |
It copy_until(It first, It last, OutIt d_first, Pred f) | |
{ | |
for (; first != last and !f(*first); ++first) | |
*d_first++ = *first; | |
return first; | |
} | |
template <char c, class It> | |
auto get_field(It first, It last, std::string& s, std::input_iterator_tag) | |
{ | |
s.clear(); | |
auto it = copy_until(first, last, std::back_inserter(s), | |
[](char v) { return v == c; }); | |
return next_maybe<c>(it, last); | |
} | |
template <char c, class It> | |
auto get_field(It first, It last, std::string& s, std::forward_iterator_tag) | |
{ | |
auto it = std::find(first, last, c); | |
s.assign(first, it); | |
return next_maybe<c>(it, last); | |
} | |
template <char c, class It, class T> | |
auto get_field(It first, It last, T& x); | |
template <char c, class It, class T> | |
auto get_field(It first, It last, T& x, std::input_iterator_tag) | |
{ | |
std::string s; | |
auto it = get_field<c>(first, last, s); | |
get_field<c>(begin(s), end(s), x); | |
return it; | |
} | |
template <char c, class It> | |
auto get_field(It first, It last, int& i, std::random_access_iterator_tag) | |
{ | |
char* p; | |
errno = 0; | |
long x = strtol(&*first, &p, 10); | |
assert(errno == 0); | |
assert(-1000000000 < x); | |
assert(x < 1000000000); | |
i = x; | |
auto diff = p - &*first; | |
std::advance(first, diff); | |
assert(first == last or *first == c); | |
return next_maybe<c>(first, last); | |
} | |
template <char c, class It> | |
auto get_field(It first, It last, double& d, std::random_access_iterator_tag) | |
{ | |
char* p; | |
errno = 0; | |
d = strtod(&*first, &p); | |
assert(errno == 0); | |
assert(std::isfinite(d)); | |
auto diff = p - &*first; | |
std::advance(first, diff); | |
assert(first == last or *first == c); | |
return next_maybe<c>(first, last); | |
} | |
template <char c, class It, class T> | |
auto get_field(It first, It last, T& x) | |
{ | |
return get_field<c>( | |
first, last, x, | |
typename std::iterator_traits<It>::iterator_category()); | |
} | |
template <class It, class T> | |
auto get_row(It first, It last, T& x) | |
{ | |
return get_field<'\n'>(first, last, x); | |
} | |
template <class It, class T, class... Ts> | |
auto get_row(It first, It last, T& x, Ts&... xs) | |
{ | |
auto it = get_field<','>(first, last, x); | |
return get_row(it, last, xs...); | |
} | |
} | |
#include <iostream> | |
void print_from_string(std::string const& S) | |
{ | |
std::string s; | |
int i; | |
double j; | |
auto it = begin(S); | |
while (it != end(S)) | |
{ | |
it = csv::get_row(it, end(S), s, i, j); | |
std::cout << s << "\t| " << i << "\t| " << j << '\n'; | |
} | |
} | |
void print_from_istream(std::istream& S) | |
{ | |
std::string s; | |
int i; | |
double j; | |
std::istreambuf_iterator<char> it(S); | |
decltype(it) last; | |
while (it != last) | |
{ | |
it = csv::get_row(it, last, s, i, j); | |
std::cout << s << "\t| " << i << "\t| " << j << '\n'; | |
} | |
} | |
int main() | |
{ | |
std::string S = "Na,1,3.24\nSea,2,300\nNa,3,100"; | |
print_from_string(S); | |
print_from_istream(std::cin); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment