Created
January 4, 2016 13:21
-
-
Save tbelaire/abcdf0dd608ba764417e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #![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