lindera_binding_core/
tokenizer.rs1use std::path::Path;
11use std::str::FromStr;
12
13use serde_json::Value;
14
15use lindera::dictionary::{Dictionary, UserDictionary};
16use lindera::mode::Mode;
17use lindera::segmenter::Segmenter;
18use lindera::tokenizer::{Tokenizer, TokenizerBuilder};
19
20use crate::error::CoreResult;
21use crate::token::TokenView;
22
23pub struct CoreTokenizerBuilder {
29 inner: TokenizerBuilder,
31}
32
33impl CoreTokenizerBuilder {
34 pub fn new() -> CoreResult<Self> {
36 Ok(Self {
37 inner: TokenizerBuilder::new()?,
38 })
39 }
40
41 pub fn from_file(file_path: &Path) -> CoreResult<Self> {
43 Ok(Self {
44 inner: TokenizerBuilder::from_file(file_path)?,
45 })
46 }
47
48 pub fn set_mode(&mut self, mode: &str) -> CoreResult<&mut Self> {
50 let mode = Mode::from_str(mode)?;
51 self.inner.set_segmenter_mode(&mode);
52 Ok(self)
53 }
54
55 pub fn set_dictionary(&mut self, uri: &str) -> &mut Self {
57 self.inner.set_segmenter_dictionary(uri);
58 self
59 }
60
61 pub fn set_user_dictionary(&mut self, uri: &str) -> &mut Self {
63 self.inner.set_segmenter_user_dictionary(uri);
64 self
65 }
66
67 pub fn set_keep_whitespace(&mut self, keep_whitespace: bool) -> &mut Self {
69 self.inner.set_segmenter_keep_whitespace(keep_whitespace);
70 self
71 }
72
73 pub fn append_character_filter(&mut self, kind: &str, args: &Value) -> &mut Self {
75 self.inner.append_character_filter(kind, args);
76 self
77 }
78
79 pub fn append_token_filter(&mut self, kind: &str, args: &Value) -> &mut Self {
81 self.inner.append_token_filter(kind, args);
82 self
83 }
84
85 pub fn build(&self) -> CoreResult<CoreTokenizer> {
87 Ok(CoreTokenizer {
88 inner: self.inner.build()?,
89 })
90 }
91}
92
93pub struct CoreTokenizer {
98 inner: Tokenizer,
100}
101
102impl CoreTokenizer {
103 pub fn from_segmenter(
105 mode: &str,
106 dictionary: Dictionary,
107 user_dictionary: Option<UserDictionary>,
108 ) -> CoreResult<Self> {
109 let mode = Mode::from_str(mode)?;
110 let segmenter = Segmenter::new(mode, dictionary, user_dictionary);
111 Ok(Self {
112 inner: Tokenizer::new(segmenter),
113 })
114 }
115
116 pub fn from_tokenizer(tokenizer: Tokenizer) -> Self {
118 Self { inner: tokenizer }
119 }
120
121 pub fn tokenize(&self, text: &str) -> CoreResult<Vec<TokenView>> {
123 let tokens = self.inner.tokenize(text)?;
124 Ok(tokens.into_iter().map(TokenView::from_token).collect())
125 }
126
127 pub fn tokenize_nbest(
129 &self,
130 text: &str,
131 n: usize,
132 unique: bool,
133 cost_threshold: Option<i64>,
134 ) -> CoreResult<Vec<(Vec<TokenView>, i64)>> {
135 let results = self.inner.tokenize_nbest(text, n, unique, cost_threshold)?;
136 Ok(results
137 .into_iter()
138 .map(|(tokens, cost)| {
139 (
140 tokens.into_iter().map(TokenView::from_token).collect(),
141 cost,
142 )
143 })
144 .collect())
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151
152 #[test]
153 fn builder_new_succeeds() {
154 assert!(CoreTokenizerBuilder::new().is_ok());
155 }
156
157 #[test]
158 fn set_mode_accepts_known_modes() {
159 let mut builder = CoreTokenizerBuilder::new().expect("builder");
160 assert!(builder.set_mode("normal").is_ok());
161 assert!(builder.set_mode("decompose").is_ok());
162 }
163
164 #[test]
165 fn set_mode_rejects_unknown_mode() {
166 let mut builder = CoreTokenizerBuilder::new().expect("builder");
167 assert!(builder.set_mode("definitely-not-a-mode").is_err());
168 }
169
170 #[test]
171 fn infallible_setters_chain() {
172 let mut builder = CoreTokenizerBuilder::new().expect("builder");
173 builder
174 .set_dictionary("embedded://ipadic")
175 .set_keep_whitespace(true)
176 .append_token_filter("japanese_compound_word", &Value::Object(Default::default()));
177 }
179}