lindera_analysis/
token_filter.rs1mod compound;
2pub mod japanese_base_form;
39pub mod japanese_compound_word;
40pub mod japanese_kana;
41pub mod japanese_katakana_stem;
42pub mod japanese_keep_tags;
43pub mod japanese_number;
44pub mod japanese_reading_form;
45pub mod japanese_stop_tags;
46pub mod keep_words;
47pub mod korean_compound_word;
48pub mod korean_keep_tags;
49pub mod korean_number;
50pub mod korean_reading_form;
51pub mod korean_stop_tags;
52pub mod length;
53pub mod lowercase;
54pub mod mapping;
55mod numeral;
56pub mod remove_diacritical_mark;
57pub mod stop_words;
58mod tags;
59pub mod uppercase;
60
61use serde_json::Value;
62use std::ops::Deref;
63
64use crate::parse_cli_flag;
65use crate::token_filter::japanese_base_form::{
66 JAPANESE_BASE_FORM_TOKEN_FILTER_NAME, JapaneseBaseFormTokenFilter,
67};
68use crate::token_filter::japanese_compound_word::{
69 JAPANESE_COMPOUND_WORD_TOKEN_FILTER_NAME, JapaneseCompoundWordTokenFilter,
70};
71use crate::token_filter::japanese_kana::{
72 JAPANESE_KANA_TOKEN_FILTER_NAME, JapaneseKanaTokenFilter,
73};
74use crate::token_filter::japanese_katakana_stem::{
75 JAPANESE_KATAKANA_STEM_TOKEN_FILTER_NAME, JapaneseKatakanaStemTokenFilter,
76};
77use crate::token_filter::japanese_keep_tags::{
78 JAPANESE_KEEP_TAGS_TOKEN_FILTER_NAME, JapaneseKeepTagsTokenFilter,
79};
80use crate::token_filter::japanese_number::{
81 JAPANESE_NUMBER_TOKEN_FILTER_NAME, JapaneseNumberTokenFilter,
82};
83use crate::token_filter::japanese_reading_form::{
84 JAPANESE_READING_FORM_TOKEN_FILTER_NAME, JapaneseReadingFormTokenFilter,
85};
86use crate::token_filter::japanese_stop_tags::{
87 JAPANESE_STOP_TAGS_TOKEN_FILTER_NAME, JapaneseStopTagsTokenFilter,
88};
89use crate::token_filter::keep_words::{KEEP_WORDS_TOKEN_FILTER_NAME, KeepWordsTokenFilter};
90use crate::token_filter::korean_compound_word::{
91 KOREAN_COMPOUND_WORD_TOKEN_FILTER_NAME, KoreanCompoundWordTokenFilter,
92};
93use crate::token_filter::korean_keep_tags::{
94 KOREAN_KEEP_TAGS_TOKEN_FILTER_NAME, KoreanKeepTagsTokenFilter,
95};
96use crate::token_filter::korean_number::{
97 KOREAN_NUMBER_TOKEN_FILTER_NAME, KoreanNumberTokenFilter,
98};
99use crate::token_filter::korean_reading_form::{
100 KOREAN_READING_FORM_TOKEN_FILTER_NAME, KoreanReadingFormTokenFilter,
101};
102use crate::token_filter::korean_stop_tags::{
103 KOREAN_STOP_TAGS_TOKEN_FILTER_NAME, KoreanStopTagsTokenFilter,
104};
105use crate::token_filter::length::{LENGTH_TOKEN_FILTER_NAME, LengthTokenFilter};
106use crate::token_filter::lowercase::{LOWERCASE_TOKEN_FILTER_NAME, LowercaseTokenFilter};
107use crate::token_filter::mapping::{MAPPING_TOKEN_FILTER_NAME, MappingTokenFilter};
108use crate::token_filter::remove_diacritical_mark::{
109 REMOVE_DIACRITICAL_TOKEN_FILTER_NAME, RemoveDiacriticalMarkTokenFilter,
110};
111use crate::token_filter::stop_words::{STOP_WORDS_TOKEN_FILTER_NAME, StopWordsTokenFilter};
112use crate::token_filter::uppercase::{UPPERCASE_TOKEN_FILTER_NAME, UppercaseTokenFilter};
113use crate::{LinderaErrorKind, LinderaResult};
114use lindera::token::Token;
115
116pub trait TokenFilter: 'static + Send + Sync + TokenFilterClone {
128 fn name(&self) -> &'static str;
129 fn apply(&self, tokens: &mut Vec<Token<'_>>) -> LinderaResult<()>;
130}
131
132pub struct BoxTokenFilter(Box<dyn TokenFilter + 'static + Send + Sync>);
138
139impl Deref for BoxTokenFilter {
140 type Target = dyn TokenFilter;
141
142 fn deref(&self) -> &dyn TokenFilter {
143 &*self.0
144 }
145}
146
147impl<T: TokenFilter> From<T> for BoxTokenFilter {
148 fn from(token_filter: T) -> BoxTokenFilter {
149 BoxTokenFilter(Box::new(token_filter))
150 }
151}
152
153pub trait TokenFilterClone {
158 fn box_clone(&self) -> BoxTokenFilter;
159}
160
161impl<T: TokenFilter + Clone + 'static> TokenFilterClone for T {
162 fn box_clone(&self) -> BoxTokenFilter {
163 BoxTokenFilter::from(self.clone())
164 }
165}
166
167pub struct TokenFilterLoader {}
168
169impl TokenFilterLoader {
170 pub fn load_from_value(kind: &str, value: &Value) -> LinderaResult<BoxTokenFilter> {
171 let token_filter = match kind {
190 JAPANESE_BASE_FORM_TOKEN_FILTER_NAME => {
191 BoxTokenFilter::from(JapaneseBaseFormTokenFilter::from_config(value)?)
192 }
193 JAPANESE_COMPOUND_WORD_TOKEN_FILTER_NAME => {
194 BoxTokenFilter::from(JapaneseCompoundWordTokenFilter::from_config(value)?)
195 }
196 JAPANESE_KANA_TOKEN_FILTER_NAME => {
197 BoxTokenFilter::from(JapaneseKanaTokenFilter::from_config(value)?)
198 }
199 JAPANESE_KATAKANA_STEM_TOKEN_FILTER_NAME => {
200 BoxTokenFilter::from(JapaneseKatakanaStemTokenFilter::from_config(value)?)
201 }
202 JAPANESE_KEEP_TAGS_TOKEN_FILTER_NAME => {
203 BoxTokenFilter::from(JapaneseKeepTagsTokenFilter::from_config(value)?)
204 }
205 JAPANESE_NUMBER_TOKEN_FILTER_NAME => {
206 BoxTokenFilter::from(JapaneseNumberTokenFilter::from_config(value)?)
207 }
208 JAPANESE_READING_FORM_TOKEN_FILTER_NAME => {
209 BoxTokenFilter::from(JapaneseReadingFormTokenFilter::from_config(value)?)
210 }
211 JAPANESE_STOP_TAGS_TOKEN_FILTER_NAME => {
212 BoxTokenFilter::from(JapaneseStopTagsTokenFilter::from_config(value)?)
213 }
214 KEEP_WORDS_TOKEN_FILTER_NAME => {
215 BoxTokenFilter::from(KeepWordsTokenFilter::from_config(value)?)
216 }
217 KOREAN_COMPOUND_WORD_TOKEN_FILTER_NAME => {
218 BoxTokenFilter::from(KoreanCompoundWordTokenFilter::from_config(value)?)
219 }
220 KOREAN_KEEP_TAGS_TOKEN_FILTER_NAME => {
221 BoxTokenFilter::from(KoreanKeepTagsTokenFilter::from_config(value)?)
222 }
223 KOREAN_NUMBER_TOKEN_FILTER_NAME => {
224 BoxTokenFilter::from(KoreanNumberTokenFilter::from_config(value)?)
225 }
226 KOREAN_READING_FORM_TOKEN_FILTER_NAME => {
227 BoxTokenFilter::from(KoreanReadingFormTokenFilter::from_config(value)?)
228 }
229 KOREAN_STOP_TAGS_TOKEN_FILTER_NAME => {
230 BoxTokenFilter::from(KoreanStopTagsTokenFilter::from_config(value)?)
231 }
232 LENGTH_TOKEN_FILTER_NAME => {
233 BoxTokenFilter::from(LengthTokenFilter::from_config(value)?)
234 }
235 LOWERCASE_TOKEN_FILTER_NAME => {
236 BoxTokenFilter::from(LowercaseTokenFilter::from_config(value)?)
237 }
238 MAPPING_TOKEN_FILTER_NAME => {
239 BoxTokenFilter::from(MappingTokenFilter::from_config(value)?)
240 }
241 REMOVE_DIACRITICAL_TOKEN_FILTER_NAME => {
242 BoxTokenFilter::from(RemoveDiacriticalMarkTokenFilter::from_config(value)?)
243 }
244 STOP_WORDS_TOKEN_FILTER_NAME => {
245 BoxTokenFilter::from(StopWordsTokenFilter::from_config(value)?)
246 }
247 UPPERCASE_TOKEN_FILTER_NAME => {
248 BoxTokenFilter::from(UppercaseTokenFilter::from_config(value)?)
249 }
250 _ => {
251 return Err(LinderaErrorKind::Deserialize
252 .with_error(anyhow::anyhow!("unsupported token filter: {kind}")));
253 }
254 };
255
256 Ok(token_filter)
257 }
258
259 pub fn load_from_cli_flag(cli_flag: &str) -> LinderaResult<BoxTokenFilter> {
285 let (kind, args) = parse_cli_flag(cli_flag)?;
286
287 let character_filter = Self::load_from_value(kind, &args)?;
288
289 Ok(character_filter)
290 }
291}