Skip to main content

sudachi/plugin/oov/
simple_oov.rs

1/*
2 * Copyright (c) 2021-2026 Works Applications Co., Ltd.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use crate::analysis::created::CreatedWords;
18use serde::Deserialize;
19use serde_json::Value;
20
21use crate::analysis::Node;
22use crate::config::Config;
23use crate::dic::grammar::Grammar;
24use crate::dic::word_id::WordId;
25use crate::input_text::InputBuffer;
26use crate::plugin::oov::OovProviderPlugin;
27use crate::plugin::PluginError;
28use crate::prelude::*;
29use crate::util::check_params::CheckParams;
30use crate::util::user_pos::{UserPosMode, UserPosSupport};
31
32/// Provides a OOV node with single character if no words found in the dictionary
33#[derive(Default)]
34pub struct SimpleOovPlugin {
35    left_id: u16,
36    right_id: u16,
37    cost: i16,
38    oov_pos_id: u16,
39}
40
41/// Struct corresponds with raw config json file.
42#[allow(non_snake_case)]
43#[derive(Deserialize)]
44struct PluginSettings {
45    oovPOS: Vec<String>,
46    leftId: i64,
47    rightId: i64,
48    cost: i64,
49    #[serde(default)]
50    userPOS: UserPosMode,
51}
52
53impl OovProviderPlugin for SimpleOovPlugin {
54    fn set_up(
55        &mut self,
56        settings: &Value,
57        _config: &Config,
58        mut grammar: &mut Grammar,
59    ) -> SudachiResult<()> {
60        let settings: PluginSettings =
61            serde_json::from_value(settings.clone()).map_err(PluginError::from)?;
62
63        self.oov_pos_id = grammar.handle_user_pos(&settings.oovPOS, settings.userPOS)?;
64        self.left_id = grammar.check_left_id(settings.leftId)?;
65        self.right_id = grammar.check_right_id(settings.rightId)?;
66        self.cost = grammar.check_cost(settings.cost)?;
67        Ok(())
68    }
69
70    fn provide_oov(
71        &self,
72        input_text: &InputBuffer,
73        offset: usize,
74        other_words: CreatedWords,
75        result: &mut Vec<Node>,
76    ) -> SudachiResult<usize> {
77        if other_words.not_empty() {
78            return Ok(0);
79        }
80
81        let length = input_text.get_word_candidate_length(offset);
82
83        result.push(Node::new(
84            offset as u16,
85            (offset + length) as u16,
86            self.left_id,
87            self.right_id,
88            self.cost,
89            WordId::oov(self.oov_pos_id as u32),
90        ));
91        Ok(1)
92    }
93}