diff --git a/src/string/pangram.rs b/src/string/pangram.rs index 3a9ad3acac7..19ccad4a688 100644 --- a/src/string/pangram.rs +++ b/src/string/pangram.rs @@ -1,5 +1,12 @@ +//! This module provides functionality to check if a given string is a pangram. +//! +//! A pangram is a sentence that contains every letter of the alphabet at least once. +//! This module can distinguish between a non-pangram, a regular pangram, and a +//! perfect pangram, where each letter appears exactly once. + use std::collections::HashSet; +/// Represents the status of a string in relation to the pangram classification. #[derive(PartialEq, Debug)] pub enum PangramStatus { NotPangram, @@ -7,48 +14,40 @@ pub enum PangramStatus { PerfectPangram, } -/// Function that checks if the slice is a pangram -/// -/// ## Arguments -/// -/// * `pangram_str` - the slice that will be checked if is a pangram -/// -/// ## Examples +fn compute_letter_counts(pangram_str: &str) -> std::collections::HashMap { + let mut letter_counts = std::collections::HashMap::new(); + + for ch in pangram_str + .to_lowercase() + .chars() + .filter(|c| c.is_ascii_alphabetic()) + { + *letter_counts.entry(ch).or_insert(0) += 1; + } + + letter_counts +} + +/// Determines if the input string is a pangram, and classifies it as either a regular or perfect pangram. /// -/// ``` -/// use the_algorithms_rust::string::is_pangram; -/// use std::collections::HashSet; -/// use the_algorithms_rust::string::PangramStatus; +/// # Arguments /// -/// assert_eq!( -/// is_pangram("This is not a pangram"), -/// PangramStatus::NotPangram -/// ); +/// * `pangram_str` - A reference to the string slice to be checked for pangram status. /// -/// assert_eq!( -/// is_pangram("The quick brown fox jumps over the lazy dog"), -/// PangramStatus::Pangram -/// ); +/// # Returns /// -/// assert_eq!( -/// is_pangram("Mr. Jock, TV quiz PhD, bags few lynx"), -/// PangramStatus::PerfectPangram -/// ); -/// ``` +/// A `PangramStatus` enum indicating whether the string is a pangram, and if so, whether it is a perfect pangram. pub fn is_pangram(pangram_str: &str) -> PangramStatus { - let alphabet: HashSet = "abcdefghijklmnopqrstuvwxyz".chars().collect(); + let letter_counts = compute_letter_counts(pangram_str); - let letters_used: HashSet = pangram_str - .to_lowercase() - .chars() - .filter(|c| c.is_ascii_alphabetic()) - .collect(); + let alphabet: HashSet = ('a'..='z').collect(); + let used_letters: HashSet<_> = letter_counts.keys().cloned().collect(); - if letters_used != alphabet { + if used_letters != alphabet { return PangramStatus::NotPangram; - }; + } - if pangram_str.chars().filter(|c| c.is_alphabetic()).count() == alphabet.len() { + if letter_counts.values().all(|&count| count == 1) { PangramStatus::PerfectPangram } else { PangramStatus::Pangram @@ -59,46 +58,35 @@ pub fn is_pangram(pangram_str: &str) -> PangramStatus { mod tests { use super::*; - #[test] - fn test_not_pangram() { - assert_eq!( - is_pangram("This is not a pangram"), - PangramStatus::NotPangram - ); - assert_eq!(is_pangram("today is a good day"), PangramStatus::NotPangram); - assert_eq!( - is_pangram( - "this is almost a pangram but it does not have bcfghjkqwxy and the last letter" - ), - PangramStatus::NotPangram - ); - } - - #[test] - fn test_pangram() { - assert_eq!( - is_pangram("The quick brown fox jumps over the lazy dog"), - PangramStatus::Pangram - ); - assert_eq!( - is_pangram("A mad boxer shot a quick, gloved jab to the jaw of his dizzy opponent"), - PangramStatus::Pangram - ); - assert_eq!( - is_pangram("Amazingly few discotheques provide jukeboxes"), - PangramStatus::Pangram - ); - assert_eq!( - is_pangram("How vexingly quick daft zebras jump"), - PangramStatus::Pangram - ); + macro_rules! pangram_tests { + ($($name:ident: $tc:expr,)*) => { + $( + #[test] + fn $name() { + let (input, expected) = $tc; + assert_eq!(is_pangram(input), expected); + } + )* + }; } - #[test] - fn test_perfect_pangram() { - assert_eq!( - is_pangram("Mr. Jock, TV quiz PhD, bags few lynx"), - PangramStatus::PerfectPangram - ); + pangram_tests! { + test_not_pangram_simple: ("This is not a pangram", PangramStatus::NotPangram), + test_not_pangram_day: ("today is a good day", PangramStatus::NotPangram), + test_not_pangram_almost: ("this is almost a pangram but it does not have bcfghjkqwxy and the last letter", PangramStatus::NotPangram), + test_pangram_standard: ("The quick brown fox jumps over the lazy dog", PangramStatus::Pangram), + test_pangram_boxer: ("A mad boxer shot a quick, gloved jab to the jaw of his dizzy opponent", PangramStatus::Pangram), + test_pangram_discotheques: ("Amazingly few discotheques provide jukeboxes", PangramStatus::Pangram), + test_pangram_zebras: ("How vexingly quick daft zebras jump", PangramStatus::Pangram), + test_perfect_pangram_jock: ("Mr. Jock, TV quiz PhD, bags few lynx", PangramStatus::PerfectPangram), + test_empty_string: ("", PangramStatus::NotPangram), + test_repeated_letter: ("aaaaa", PangramStatus::NotPangram), + test_non_alphabetic: ("12345!@#$%", PangramStatus::NotPangram), + test_mixed_case_pangram: ("ThE QuiCk BroWn FoX JumPs OveR tHe LaZy DoG", PangramStatus::Pangram), + test_perfect_pangram_with_symbols: ("Mr. Jock, TV quiz PhD, bags few lynx!", PangramStatus::PerfectPangram), + test_long_non_pangram: (&"a".repeat(1000), PangramStatus::NotPangram), + test_near_pangram_missing_one_letter: ("The quick brown fox jumps over the lazy do", PangramStatus::NotPangram), + test_near_pangram_missing_two_letters: ("The quick brwn f jumps ver the lazy dg", PangramStatus::NotPangram), + test_near_pangram_with_special_characters: ("Th3 qu!ck brown f0x jumps 0v3r th3 l@zy d0g.", PangramStatus::NotPangram), } }