#include <fstream>
#include <string>
#include <iostream>
namespace {
void replace_col(const char* inpath, const char* outpath, const char* label,
const char* replacement)
{
std::ifstream infile(inpath);
if(! infile.good())
throw std::ios::failure("Cannot open input");
infile.exceptions(std::ios::badbit);
std::ofstream outfile(outpath);
if(! outfile.good())
throw std::ios::failure("Cannot create output");
outfile.exceptions(std::ios::badbit | std::ios::failbit);
std::string buf;
if(! std::getline(infile, buf))
return; // empty file
// Handle header. Look for column index
int replacecol = 0;
bool found;
// we stop when we haven't found a separator in the last iteration
for(std::size_t offset = 0, cursep = 0; cursep != std::string::npos;
++replacecol, offset = cursep + 1) {
cursep = buf.find(',', offset);
if((found = ! buf.compare(offset, cursep - offset, label)))
break;
}
if(! found)
throw std::ios::failure("Column not found");
outfile << buf << '\n'; // save header unchanged
while(std::getline(infile, buf)) {
std::size_t offset, cursep;
int curcol;
for(offset = 0, cursep = 0, curcol = 0; cursep != std::string::npos;
++curcol, offset = cursep + 1) {
cursep = buf.find(',', offset);
if(offset) // add separator to previous column
outfile << ',';
/*
* one loop before the replacement and one after it would be more
* efficient but let's keep it simple
*/
if(curcol == replacecol)
outfile << replacement;
else
outfile << buf.substr(offset, cursep - offset);
}
outfile << '\n';
}
// don't rely on dtor so that we can catch IO errors
outfile.close();
}
}
int main(int argc, char** argv)
{
if(argc != 5) {
std::cerr << "Usage: " << argv[0]
<< " INPUT.csv COLUMN REPLACEMENT OUTPUT.csv\n";
return 1;
}
replace_col(argv[1], argv[4], argv[2], argv[3]);
}
Comments