Skip to content

Instantly share code, notes, and snippets.

@boxdot
Created November 4, 2017 22:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save boxdot/8abd5eccec95dd74d0a35d33463ae53b to your computer and use it in GitHub Desktop.
Save boxdot/8abd5eccec95dd74d0a35d33463ae53b to your computer and use it in GitHub Desktop.
use std::fs::File;
use std::io::BufRead;
use std::io::Write;
use std::path::PathBuf;
#[derive(Debug)]
struct Args {
input: PathBuf,
column: String,
replacement: String,
output: PathBuf,
}
#[inline]
fn parse_args() -> Result<Args, String> {
let mut args = std::env::args();
args.next();
Ok(Args {
input: PathBuf::from(args.next().ok_or(String::from("Missing input argument"))?),
column: args.next().ok_or(String::from("Missing column argument"))?,
replacement: args.next().ok_or(String::from("Missing column argument"))?,
output: PathBuf::from(args.next().ok_or(String::from("Missing input argument"))?),
})
}
#[inline]
fn find_column(line: &str, column: &str) -> Option<usize> {
for (index, token) in line.split(",").enumerate() {
if token == column {
return Some(index);
}
}
None
}
#[inline]
fn output_err<T>(err: T) -> String
where
T: std::fmt::Debug,
{
format!("Could not write to output file: {:?}", err)
}
fn do_work(args: Args) -> Result<(), String> {
// open file
let fin = File::open(args.input).map_err(|err| {
format!("Could not open input file: {}", err)
})?;
let mut input = std::io::BufReader::new(fin);
// find column in header
let mut line = String::new();
input.read_line(&mut line).map_err(|err| {
format!("Could not read header: {}", err)
})?;
let column_index = find_column(&line, &args.column).ok_or(String::from(
"Could not find column",
))?;
// open output
let fout = File::create(args.output).map_err(|err| {
format!("Could not open input file: {}", err)
})?;
let mut output = std::io::BufWriter::new(fout);
output.write(line.as_bytes()).map_err(output_err)?;
// replace
for line in input.lines() {
for (index, token) in line.map_err(output_err)?.split(",").enumerate() {
if index > 0 {
output.write(b",").map_err(output_err)?;
}
if index == column_index {
output.write(args.replacement.as_bytes()).map_err(
output_err,
)?;
} else {
output.write(token.as_bytes()).map_err(output_err)?;
}
}
output.write(b"\n").map_err(output_err)?;
}
Ok(())
}
fn main() {
let args = parse_args();
let res = args.and_then(do_work);
::std::process::exit(match res {
Ok(_) => 0,
Err(err) => {
eprintln!(
"Error: {}\n\nUSAGE: csv <INPUT> <COLUMN> <REPLACEMENT> <OUTPUT>",
err
);
1
}
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment