#include #include #include 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]); }