use super::Stopwords;
use super::is_bare_punctuation;
use super::is_special_token;
use super::stem;
const MAX_STEM_LENGTH: usize = 40;
pub(super) fn resplit(word: &str, stopwords: &Stopwords) -> Vec<String> {
word
.chars()
.map(|c| if is_word_or_space(c) { c } else { ' ' })
.collect::<String>()
.split_whitespace()
.filter(|subword| survives(&stem(subword), stopwords))
.map(str::to_string)
.collect()
}
fn is_word_or_space(c: char) -> bool {
c.is_alphanumeric() || c == '_' || c.is_whitespace()
}
fn survives(stemmed: &str, stopwords: &Stopwords) -> bool {
stemmed.chars().count() <= MAX_STEM_LENGTH
&& !is_special_token(stemmed)
&& !stopwords.contains(stemmed)
&& !is_bare_punctuation(stemmed)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_word_with_one_embedded_non_word_character_cleans_to_its_word_characters() {
let stopwords = Stopwords::parse("");
assert_eq!(resplit("9°", &stopwords), vec!["9".to_string()]);
}
#[test]
fn a_word_built_entirely_from_non_word_characters_yields_no_survivors() {
let stopwords = Stopwords::parse("");
assert!(resplit("...", &stopwords).is_empty());
assert!(resplit("<", &stopwords).is_empty());
assert!(resplit("=", &stopwords).is_empty());
}
#[test]
fn a_word_with_an_embedded_separator_splits_into_both_sides() {
let stopwords = Stopwords::parse("");
assert_eq!(
resplit("cat!dog", &stopwords),
vec!["cat".to_string(), "dog".to_string()]
);
}
#[test]
fn a_subword_is_dropped_when_its_own_stem_is_a_stopword() {
let stopwords = Stopwords::parse("on\n");
assert!(resplit("ons", &stopwords).is_empty());
}
#[test]
fn a_subword_stemming_past_the_forty_character_cap_is_dropped() {
let stopwords = Stopwords::parse("");
let long = "a".repeat(41);
assert!(resplit(&long, &stopwords).is_empty());
let short = "a".repeat(40);
assert_eq!(resplit(&short, &stopwords), vec![short]);
}
#[test]
fn an_ordinary_word_with_nothing_to_clean_is_unchanged() {
let stopwords = Stopwords::parse("");
assert_eq!(resplit("xyzzy", &stopwords), vec!["xyzzy".to_string()]);
}
}