lindera_analysis/token_filter/
length.rs1use serde_json::Value;
2
3use crate::token_filter::TokenFilter;
4use lindera::LinderaResult;
5use lindera::token::Token;
6
7pub const LENGTH_TOKEN_FILTER_NAME: &str = "length";
8
9pub type LengthTokenFilterConfig = Value;
10
11#[derive(Clone, Debug)]
14pub struct LengthTokenFilter {
15 min: Option<usize>,
16 max: Option<usize>,
17}
18
19impl LengthTokenFilter {
20 pub fn new(min: Option<usize>, max: Option<usize>) -> Self {
21 Self { min, max }
22 }
23
24 pub fn from_config(config: &LengthTokenFilterConfig) -> LinderaResult<Self> {
25 let min: Option<usize> = config
26 .get("min")
27 .and_then(|v| v.as_u64())
28 .map(|v| v as usize);
29 let max: Option<usize> = config
30 .get("max")
31 .and_then(|v| v.as_u64())
32 .map(|v| v as usize);
33
34 Ok(Self::new(min, max))
35 }
36}
37
38impl TokenFilter for LengthTokenFilter {
39 fn name(&self) -> &'static str {
40 LENGTH_TOKEN_FILTER_NAME
41 }
42
43 fn apply(&self, tokens: &mut Vec<Token<'_>>) -> LinderaResult<()> {
44 tokens.retain(|token| {
45 let len = token.surface.chars().count();
46 if let Some(min) = self.min
47 && len < min
48 {
49 return false;
50 }
51 if let Some(max) = self.max
52 && len > max
53 {
54 return false;
55 }
56 true
57 });
58
59 Ok(())
60 }
61}
62
63#[cfg(test)]
64mod tests {
65 use crate::token_filter::length::{LengthTokenFilter, LengthTokenFilterConfig};
66
67 #[test]
68 fn test_length_token_filter_confige() {
69 let config_str = r#"
70 {
71 "min": 1,
72 "max": 3
73 }
74 "#;
75 let result: Result<LengthTokenFilterConfig, _> = serde_json::from_str(config_str);
76 assert!(result.is_ok());
77
78 let config_str = r#"
79 {
80 "min": 1
81 }
82 "#;
83 let result: Result<LengthTokenFilterConfig, _> = serde_json::from_str(config_str);
84 assert!(result.is_ok());
85
86 let config_str = r#"
87 {
88 "max": 2
89 }
90 "#;
91 let result: Result<LengthTokenFilterConfig, _> = serde_json::from_str(config_str);
92 assert!(result.is_ok());
93 }
94
95 #[test]
96 fn test_length_token_filter() {
97 let config_str = r#"
98 {
99 "min": 1,
100 "max": 3
101 }
102 "#;
103 let config: LengthTokenFilterConfig = serde_json::from_str(config_str).unwrap();
104 let result = LengthTokenFilter::from_config(&config);
105 assert!(result.is_ok());
106
107 let config_str = r#"
108 {
109 "min": 1
110 }
111 "#;
112 let config: LengthTokenFilterConfig = serde_json::from_str(config_str).unwrap();
113 let result = LengthTokenFilter::from_config(&config);
114 assert!(result.is_ok());
115
116 let config_str = r#"
117 {
118 "max": 2
119 }
120 "#;
121 let config: LengthTokenFilterConfig = serde_json::from_str(config_str).unwrap();
122 let result = LengthTokenFilter::from_config(&config);
123 assert!(result.is_ok());
124 }
125
126 #[test]
127 #[cfg(feature = "embed-ipadic")]
128 fn test_length_token_filter_apply_ipadic() {
129 use std::borrow::Cow;
130
131 use crate::token_filter::TokenFilter;
132 use lindera::dictionary::{DictionaryKind, WordId, load_embedded_dictionary};
133 use lindera::token::Token;
134 use lindera_dictionary::viterbi::LexType;
135
136 let config_str = r#"
137 {
138 "min": 2,
139 "max": 3
140 }
141 "#;
142 let config: LengthTokenFilterConfig = serde_json::from_str(config_str).unwrap();
143 let filter = LengthTokenFilter::from_config(&config).unwrap();
144
145 let dictionary = load_embedded_dictionary(DictionaryKind::IPADIC).unwrap();
146
147 let mut tokens: Vec<Token> = vec![
148 Token {
149 surface: Cow::Borrowed("すもも"),
150 byte_start: 0,
151 byte_end: 9,
152 position: 0,
153 position_length: 1,
154 word_id: WordId::new(LexType::System, 36165),
155 dictionary: &dictionary,
156 user_dictionary: None,
157 details: Some(vec![
158 Cow::Borrowed("名詞"),
159 Cow::Borrowed("一般"),
160 Cow::Borrowed("*"),
161 Cow::Borrowed("*"),
162 Cow::Borrowed("*"),
163 Cow::Borrowed("*"),
164 Cow::Borrowed("すもも"),
165 Cow::Borrowed("スモモ"),
166 Cow::Borrowed("スモモ"),
167 ]),
168 },
169 Token {
170 surface: Cow::Borrowed("も"),
171 byte_start: 9,
172 byte_end: 12,
173 position: 1,
174 position_length: 1,
175 word_id: WordId::new(LexType::System, 73246),
176 dictionary: &dictionary,
177 user_dictionary: None,
178 details: Some(vec![
179 Cow::Borrowed("助詞"),
180 Cow::Borrowed("係助詞"),
181 Cow::Borrowed("*"),
182 Cow::Borrowed("*"),
183 Cow::Borrowed("*"),
184 Cow::Borrowed("*"),
185 Cow::Borrowed("も"),
186 Cow::Borrowed("モ"),
187 Cow::Borrowed("モ"),
188 ]),
189 },
190 Token {
191 surface: Cow::Borrowed("もも"),
192 byte_start: 12,
193 byte_end: 18,
194 position: 2,
195 position_length: 1,
196 word_id: WordId::new(LexType::System, 74990),
197 dictionary: &dictionary,
198 user_dictionary: None,
199 details: Some(vec![
200 Cow::Borrowed("名詞"),
201 Cow::Borrowed("一般"),
202 Cow::Borrowed("*"),
203 Cow::Borrowed("*"),
204 Cow::Borrowed("*"),
205 Cow::Borrowed("*"),
206 Cow::Borrowed("もも"),
207 Cow::Borrowed("モモ"),
208 Cow::Borrowed("モモ"),
209 ]),
210 },
211 Token {
212 surface: Cow::Borrowed("も"),
213 byte_start: 18,
214 byte_end: 21,
215 position: 3,
216 position_length: 1,
217 word_id: WordId::new(LexType::System, 73246),
218 dictionary: &dictionary,
219 user_dictionary: None,
220 details: Some(vec![
221 Cow::Borrowed("助詞"),
222 Cow::Borrowed("係助詞"),
223 Cow::Borrowed("*"),
224 Cow::Borrowed("*"),
225 Cow::Borrowed("*"),
226 Cow::Borrowed("*"),
227 Cow::Borrowed("も"),
228 Cow::Borrowed("モ"),
229 Cow::Borrowed("モ"),
230 ]),
231 },
232 Token {
233 surface: Cow::Borrowed("もも"),
234 byte_start: 21,
235 byte_end: 27,
236 position: 4,
237 position_length: 1,
238 word_id: WordId::new(LexType::System, 74990),
239 dictionary: &dictionary,
240 user_dictionary: None,
241 details: Some(vec![
242 Cow::Borrowed("名詞"),
243 Cow::Borrowed("一般"),
244 Cow::Borrowed("*"),
245 Cow::Borrowed("*"),
246 Cow::Borrowed("*"),
247 Cow::Borrowed("*"),
248 Cow::Borrowed("もも"),
249 Cow::Borrowed("モモ"),
250 Cow::Borrowed("モモ"),
251 ]),
252 },
253 Token {
254 surface: Cow::Borrowed("の"),
255 byte_start: 27,
256 byte_end: 30,
257 position: 5,
258 position_length: 1,
259 word_id: WordId::new(LexType::System, 55831),
260 dictionary: &dictionary,
261 user_dictionary: None,
262 details: Some(vec![
263 Cow::Borrowed("助詞"),
264 Cow::Borrowed("連体化"),
265 Cow::Borrowed("*"),
266 Cow::Borrowed("*"),
267 Cow::Borrowed("*"),
268 Cow::Borrowed("*"),
269 Cow::Borrowed("の"),
270 Cow::Borrowed("ノ"),
271 Cow::Borrowed("ノ"),
272 ]),
273 },
274 Token {
275 surface: Cow::Borrowed("うち"),
276 byte_start: 30,
277 byte_end: 36,
278 position: 6,
279 position_length: 1,
280 word_id: WordId::new(LexType::System, 8029),
281 dictionary: &dictionary,
282 user_dictionary: None,
283 details: Some(vec![
284 Cow::Borrowed("名詞"),
285 Cow::Borrowed("非自立"),
286 Cow::Borrowed("副詞可能"),
287 Cow::Borrowed("*"),
288 Cow::Borrowed("*"),
289 Cow::Borrowed("*"),
290 Cow::Borrowed("うち"),
291 Cow::Borrowed("ウチ"),
292 Cow::Borrowed("ウチ"),
293 ]),
294 },
295 ];
296
297 filter.apply(&mut tokens).unwrap();
298
299 assert_eq!(tokens.len(), 4);
300 assert_eq!(&tokens[0].surface, "すもも");
301 assert_eq!(&tokens[1].surface, "もも");
302 assert_eq!(&tokens[2].surface, "もも");
303 assert_eq!(&tokens[3].surface, "うち");
304 }
305}