Skip to content

Instantly share code, notes, and snippets.

@tbelaire
Created January 4, 2016 13:21
Show Gist options
  • Select an option

  • Save tbelaire/abcdf0dd608ba764417e to your computer and use it in GitHub Desktop.

Select an option

Save tbelaire/abcdf0dd608ba764417e to your computer and use it in GitHub Desktop.
#![allow(non_snake_case)]
extern crate argparse;
use argparse::{ArgumentParser, StoreTrue, Store};
use std::fs::File;
use std::str::FromStr;
use std::io::{BufReader, BufRead};
use std::collections::HashMap;
#[derive(Debug)]
enum Mode {
Encode,
Decode,
}
impl FromStr for Mode {
type Err = ();
fn from_str(src: &str) -> Result<Mode, ()> {
match src {
"encode" => Ok(Mode::Encode),
"decode" => Ok(Mode::Decode),
_ => Err(()),
}
}
}
fn parse_dict(input: String) -> HashMap<String, String> {
let owned_slice: Vec<&str> = input.trim().split(' ').collect();
assert!(owned_slice.len() % 2 == 0, "Odd number of chunks");
owned_slice.chunks(2)
.map(|slice| (slice[1].to_owned(), slice[0].to_owned()))
.collect()
}
fn decode(in_file: &mut BufRead, verbose: bool) -> String {
let mut first_line = String::new();
in_file.read_line(&mut first_line).unwrap();
if verbose {
println!("first line is:\n{}", first_line);
}
let dict = parse_dict(first_line);
if verbose {
println!("dict is: {:?}", dict);
}
let mut input = String::new();
in_file.read_to_string(&mut input).unwrap();
let mut output = String::new();
let mut left = Some(0);
for (ix, ch) in input.char_indices() {
if verbose {
println!("Considering ix, ch = ({:?}, {:?})", ix, ch);
}
// If we have a previous offset as a left bound.
if let Some(left_ix) = left {
if verbose {
println!("Considering '{}'", &input[left_ix..ix]);
}
// Check the range up to but not include the new character
if let Some(val) = dict.get(&input[left_ix..ix]) {
if verbose {
println!("output: {}", val);
}
output.push_str(&val);
left = None;
} else {
if verbose {
println!("incomplete prefix");
}
}
}
if ch != 'G' && ch != 'g' {
assert!(left == None, "Unconsumed prefix");
if verbose {
println!("output: {}", ch);
}
output.push(ch);
left = None;
} else if left == None {
// Start a new pattern with the g or G
left = Some(ix);
} else {
// Expand the existing pattern
}
}
output
}
fn main() {
let mut verbose = false;
let mut input_file = "-".to_owned();
// Encode or decode
let mut mode: Mode = Mode::Encode; // Not the default, always written to.
{
let mut ap = ArgumentParser::new();
ap.set_description("Encode or decode gGgggG text.");
ap.refer(&mut verbose)
.add_option(&["-v", "--verbose"], StoreTrue, "Be verbose");
ap.refer(&mut mode)
.required()
.add_argument("mode",
Store,
r#"Either "encode" or "decode" the input"#);
ap.refer(&mut input_file)
.add_argument("input file", Store, "file to read. '-' means stdin");
ap.parse_args_or_exit();
}
if verbose {
println!("Mode is {:?}", mode);
println!("input_file {:?}", input_file);
}
match mode {
Mode::Decode => {
let mut file = if input_file == "-" {
let f = std::io::stdin();
Box::new(BufReader::new(f)) as Box<BufRead>
} else {
let f = File::open(&input_file).unwrap();
Box::new(BufReader::new(f)) as Box<BufRead>
};
let output = decode(&mut file, verbose);
print!("{}", output);
}
Mode::Encode => unimplemented!(),
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment