Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
),
}
}