Skip to content

Commit

Permalink
Improve Lipogram (#821)
Browse files Browse the repository at this point in the history
ref: improve lipogram
  • Loading branch information
sozelfist authored Oct 16, 2024
1 parent d0f258a commit 3139471
Showing 1 changed file with 78 additions and 59 deletions.
137 changes: 78 additions & 59 deletions src/string/lipogram.rs
Original file line number Diff line number Diff line change
@@ -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<char>` containing the lowercase alphabetic characters that are not present in `in_str`.
fn compute_missing(in_str: &str) -> HashSet<char> {
let alphabet: HashSet<char> = "abcdefghijklmnopqrstuvwxyz".chars().collect();
let alphabet: HashSet<char> = ('a'..='z').collect();

let letters_used: HashSet<char> = in_str
.to_lowercase()
Expand All @@ -19,75 +30,83 @@ fn compute_missing(in_str: &str) -> HashSet<char> {
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<char>` 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<char>) -> 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<char>,
) -> Result<bool, LipogramError> {
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)
),
}
}

0 comments on commit 3139471

Please sign in to comment.