language_text_analysis/
analyzer.rs1use rust_stemmers::Stemmer;
5
6use crate::language::Language;
7use crate::normalize::normalize;
8use crate::term::Term;
9use crate::tokenize::tokenize;
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13pub enum StopWordPolicy {
14 DefaultForLanguage,
16 None,
18}
19
20impl StopWordPolicy {
21 fn removes(self, language: Language, token: &str) -> bool {
24 match self {
25 Self::DefaultForLanguage => language.stop_words().contains(&token),
26 Self::None => false,
27 }
28 }
29}
30
31#[derive(Clone, Debug)]
40pub struct Analyzer {
41 default_language: Language,
42 stop_words: StopWordPolicy,
43 stemming: bool,
44}
45
46impl Analyzer {
47 #[must_use]
50 pub fn new() -> Self {
51 Self {
52 default_language: Language::English,
53 stop_words: StopWordPolicy::DefaultForLanguage,
54 stemming: false,
55 }
56 }
57
58 #[must_use]
60 pub fn builder() -> AnalyzerBuilder {
61 AnalyzerBuilder::new()
62 }
63
64 #[must_use]
67 pub fn default_language(&self) -> Language {
68 self.default_language
69 }
70
71 #[must_use]
82 pub fn analyze(&self, text: &str, lang_tag: Option<&str>) -> Vec<Term> {
83 let language = lang_tag
84 .and_then(Language::from_tag)
85 .unwrap_or(self.default_language);
86 let normalized = normalize(text);
87 let stemmer = self
88 .stemming
89 .then(|| Stemmer::create(language.stemmer_algorithm()));
90
91 let mut terms = Vec::new();
94 for token in tokenize(&normalized) {
95 if self.stop_words.removes(language, token) {
96 continue;
97 }
98 let term = match &stemmer {
99 Some(stemmer) => Term::from_normalized(stemmer.stem(token).into_owned()),
100 None => Term::from_normalized(token),
101 };
102 terms.push(term);
103 }
104 terms
105 }
106}
107
108impl Default for Analyzer {
109 fn default() -> Self {
110 Self::new()
111 }
112}
113
114#[derive(Clone, Debug)]
116pub struct AnalyzerBuilder {
117 default_language: Language,
118 stop_words: StopWordPolicy,
119 stemming: bool,
120}
121
122impl AnalyzerBuilder {
123 fn new() -> Self {
124 Self {
125 default_language: Language::English,
126 stop_words: StopWordPolicy::DefaultForLanguage,
127 stemming: false,
128 }
129 }
130
131 #[must_use]
133 pub fn default_language(mut self, language: Language) -> Self {
134 self.default_language = language;
135 self
136 }
137
138 #[must_use]
140 pub fn stop_words(mut self, policy: StopWordPolicy) -> Self {
141 self.stop_words = policy;
142 self
143 }
144
145 #[must_use]
147 pub fn stemming(mut self, enabled: bool) -> Self {
148 self.stemming = enabled;
149 self
150 }
151
152 #[must_use]
154 pub fn build(self) -> Analyzer {
155 Analyzer {
156 default_language: self.default_language,
157 stop_words: self.stop_words,
158 stemming: self.stemming,
159 }
160 }
161}
162
163impl Default for AnalyzerBuilder {
164 fn default() -> Self {
165 Self::new()
166 }
167}