-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
Copy pathlipogram.rs
112 lines (102 loc) · 3.48 KB
/
lipogram.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use std::collections::HashSet;
/// 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
///
/// * `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> = ('a'..='z').collect();
let letters_used: HashSet<char> = in_str
.to_lowercase()
.chars()
.filter(|c| c.is_ascii_alphabetic())
.collect();
alphabet.difference(&letters_used).cloned().collect()
}
/// Checks if the provided string is a lipogram, meaning it is missing specific characters.
///
/// # Arguments
///
/// * `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.
///
/// # Returns
///
/// 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);
}
}
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: $tc:expr,)*) => {
$(
#[test]
fn $name() {
let (input, missing_chars, expected) = $tc;
assert_eq!(is_lipogram(input, &missing_chars), expected);
}
)*
}
}
test_lipogram! {
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)
),
}
}