From 3139471a2357bcd92f1ac0896e4d5ae46cee5339 Mon Sep 17 00:00:00 2001 From: Truong Nhan Nguyen <80200848+sozelfist@users.noreply.github.com> Date: Thu, 17 Oct 2024 00:45:05 +0700 Subject: [PATCH] Improve Lipogram (#821) ref: improve lipogram --- src/string/lipogram.rs | 137 +++++++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 59 deletions(-) diff --git a/src/string/lipogram.rs b/src/string/lipogram.rs index 93f7d3dce6b..9a486c2a62d 100644 --- a/src/string/lipogram.rs +++ b/src/string/lipogram.rs @@ -1,14 +1,25 @@ use std::collections::HashSet; -/// Function that returns the letters that are missing from the input slice -/// and are present in the English alphabet +/// Represents possible errors that can occur when checking for lipograms. +#[derive(Debug, PartialEq, Eq)] +pub enum LipogramError { + /// Indicates that a non-alphabetic character was found in the input. + NonAlphabeticCharacter, + /// Indicates that a missing character is not in lowercase. + NonLowercaseMissingChar, +} + +/// Computes the set of missing alphabetic characters from the input string. /// -/// ## Arguments +/// # Arguments /// -/// * `in_str` - the slice that will be checked for missing characters +/// * `in_str` - A string slice that contains the input text. /// +/// # Returns +/// +/// Returns a `HashSet` containing the lowercase alphabetic characters that are not present in `in_str`. fn compute_missing(in_str: &str) -> HashSet { - let alphabet: HashSet = "abcdefghijklmnopqrstuvwxyz".chars().collect(); + let alphabet: HashSet = ('a'..='z').collect(); let letters_used: HashSet = in_str .to_lowercase() @@ -19,75 +30,83 @@ fn compute_missing(in_str: &str) -> HashSet { alphabet.difference(&letters_used).cloned().collect() } -/// Function that checks if the slice is a lipogram with specific missing letters. -/// Lipogram - sentence in which a particular letter or group of letters is avoided -/// -/// ## Arguments +/// Checks if the provided string is a lipogram, meaning it is missing specific characters. /// -/// * `lipogram_str` - the slice that will be checked if is a lipogram with specific missing letters -/// * `missing_chars` - the characters that has to be missing +/// # Arguments /// -/// ## Examples +/// * `lipogram_str` - A string slice that contains the text to be checked for being a lipogram. +/// * `missing_chars` - A reference to a `HashSet` containing the expected missing characters. /// -/// ``` -/// use the_algorithms_rust::string::is_lipogram; -/// use std::collections::HashSet; +/// # Returns /// -/// assert!( -/// !is_lipogram("The quick brown fox jumps over the lazy dog", -/// &HashSet::from(['x']) -/// )); -/// -/// assert!( -/// is_lipogram("The brown cat jumped over the lazy dog with a brick", -/// &HashSet::from(['f', 'q', 's', 'x']) -/// )); -/// -/// assert!( -/// !is_lipogram("The quick brown fox jumped over the lazy dog", -/// &HashSet::from(['x']) -/// )); -/// ``` -pub fn is_lipogram(lipogram_str: &str, missing_chars: &HashSet) -> bool { - if !missing_chars.iter().all(|&c| c.is_lowercase()) { - panic!("missing_chars should be all lowercase.") +/// Returns `Ok(true)` if the string is a lipogram that matches the provided missing characters, +/// `Ok(false)` if it does not match, or a `LipogramError` if the input contains invalid characters. +pub fn is_lipogram( + lipogram_str: &str, + missing_chars: &HashSet, +) -> Result { + for &c in missing_chars { + if !c.is_lowercase() { + return Err(LipogramError::NonLowercaseMissingChar); + } } - missing_chars == &compute_missing(lipogram_str) + for c in lipogram_str.chars() { + if !c.is_ascii_alphabetic() && !c.is_whitespace() { + return Err(LipogramError::NonAlphabeticCharacter); + } + } + + let missing = compute_missing(lipogram_str); + Ok(missing == *missing_chars) } #[cfg(test)] mod tests { use super::*; + macro_rules! test_lipogram { - ($($name:ident: $inputs:expr,)*) => { - $( - #[test] - fn $name() { - let (in_str, missing_chars, other_chars) = $inputs; - assert_ne!(missing_chars, other_chars); - assert_eq!(compute_missing(in_str), missing_chars); - assert!(is_lipogram(in_str, &missing_chars)); - assert!(!is_lipogram(in_str, &other_chars)); + ($($name:ident: $tc:expr,)*) => { + $( + #[test] + fn $name() { + let (input, missing_chars, expected) = $tc; + assert_eq!(is_lipogram(input, &missing_chars), expected); + } + )* } - )* } -} test_lipogram! { - lipogram1: ("The quick brown fox jumps over the lazy dog", HashSet::from([]), HashSet::from(['a', 'b'])), - lipogram2: ("Jackdaws love my big sphinx of quartz", HashSet::from([]), HashSet::from(['x'])), - lipogram3: ("abcdefghijklmnopqrstuvwxyz", HashSet::from([]), HashSet::from(['x', 'y', 'z'])), - lipogram4: ("Five quacking zephyrs jolt my wax bed", HashSet::from([]), HashSet::from(['a'])), - lipogram5: ("The quick brown fox jumped over the lazy dog", HashSet::from(['s']), HashSet::from([])), - lipogram6: ("abcdefghijklmnopqrstuvwxy", HashSet::from(['z']), HashSet::from(['y', 'z'])), - lipogram7: ("The brown fox jumped over the lazy dog with a brick", HashSet::from(['q', 's']), HashSet::from(['b'])), - lipogram8: ("ABCdefghijklmnopqrstuvwx", HashSet::from(['y', 'z']), HashSet::from(['a', 'b'])), - } - - #[test] - #[should_panic] - fn test_is_lipogram_panics_when_missing_chars_are_upper_case() { - is_lipogram("abcdefghijklmnopqrstuvwx", &HashSet::from(['y', 'Z'])); + perfect_pangram: ( + "The quick brown fox jumps over the lazy dog", + HashSet::from([]), + Ok(true) + ), + lipogram_single_missing: ( + "The quick brown fox jumped over the lazy dog", + HashSet::from(['s']), + Ok(true) + ), + lipogram_multiple_missing: ( + "The brown fox jumped over the lazy dog", + HashSet::from(['q', 'i', 'c', 'k', 's']), + Ok(true) + ), + long_lipogram_single_missing: ( + "A jovial swain should not complain of any buxom fair who mocks his pain and thinks it gain to quiz his awkward air", + HashSet::from(['e']), + Ok(true) + ), + invalid_non_lowercase_chars: ( + "The quick brown fox jumped over the lazy dog", + HashSet::from(['X']), + Err(LipogramError::NonLowercaseMissingChar) + ), + invalid_non_alphabetic_input: ( + "The quick brown fox jumps over the lazy dog 123@!", + HashSet::from([]), + Err(LipogramError::NonAlphabeticCharacter) + ), } }