Skip to content

Instantly share code, notes, and snippets.

@lichray
Created August 10, 2018 05:01
Show Gist options
  • Save lichray/400875699c490eed11000861472ccb1e to your computer and use it in GitHub Desktop.
Save lichray/400875699c490eed11000861472ccb1e to your computer and use it in GitHub Desktop.
A tiny CSV data reader for online coding tests
#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