use std::io::stdin; use std::io::BufRead; use std::io::BufReader; /// Words that will not be capitalized unless they are at the start or end of a title. const EXCEPTIONS: &[&str] = &[ "vs", "above", "across", "against", "at", "between", "by", "along", "among", "down", "in", "around", "of", "off", "on", "to", "with", "before", "behind", "below", "beneath", "down", "from", "near", "toward", "upon", "within", "a", "an", "the", "and", "but", "for", "or", "nor", "yet", "so", ]; /// Here are the rules: /// /// - Every line is its own title. No multi-line titles. /// - All words are capitalized, except... /// - Words are not capitalized if they are EXCEPTIONS, unless... /// - Words are either the first or the last word. fn main() { for line in BufReader::new(stdin()).lines() { println!("{}", capitalize_line(&line.expect("IO error"))); } } /// Capitalizes a single line (title) based on placement and exceptions. fn capitalize_line(line: &str) -> String { let mut line = line.split_whitespace().map(str::to_lowercase).peekable(); let mut result: Vec = Vec::new(); // handle first word let first = line.next().expect("No words on line"); result.push(capitalize_word(&first)); while let Some(word) = line.next() { let word = if line.peek().is_none() || !EXCEPTIONS.contains(&word.as_str()) { // capitalize words that are last or aren't in exceptions capitalize_word(&word) } else { // ignore the rest word }; result.push(word); } // join words into title result.join(" ") } /// Capitalizes a single word. fn capitalize_word(word: &str) -> String { let mut chars = word.chars(); let first = chars.next().unwrap(); format!("{}{}", first.to_uppercase(), chars.collect::()) } #[cfg(test)] mod tests { // Note this useful idiom: importing names from outer (for mod tests) scope. use super::*; #[test] fn test_capitalize_word() { assert_eq!(capitalize_word("word"), String::from("Word")); assert_eq!(capitalize_word("as"), String::from("As")); } #[test] fn test_capitalize_line() { assert_eq!( capitalize_line("this is a test"), String::from("This Is a Test") ); assert_eq!( capitalize_line("similEs: lIke Or As"), String::from("Similes: Like or As") ); } }