use std::sync::Arc;
use super::filters::{self, CompiledFilter};
use super::{
KoreanFilter, KoreanTokenizer, NoriDictionary, NoriLimits, NoriOptions, NoriOutput,
UserDictionary,
};
use crate::AnalysisResult;
use uqa_core::memory::{Budgeted, MemoryBudget};
#[derive(Debug, Clone)]
pub struct KoreanAnalyzer {
model: Arc<NoriDictionary>,
tokenizer: KoreanTokenizer,
filters: Vec<CompiledFilter>,
}
impl KoreanAnalyzer {
pub fn new(
model: Arc<NoriDictionary>,
user: Option<Arc<UserDictionary>>,
options: NoriOptions,
) -> AnalysisResult<Self> {
Self::with_filters(
model,
user,
options,
&[
KoreanFilter::PartOfSpeech { stop_tags: None },
KoreanFilter::ReadingForm,
KoreanFilter::SimpleLowercase,
],
)
}
pub fn with_filters(
model: Arc<NoriDictionary>,
user: Option<Arc<UserDictionary>>,
options: NoriOptions,
filters: &[KoreanFilter],
) -> AnalysisResult<Self> {
let tokenizer = KoreanTokenizer::new(model.clone(), user, options)?;
let mut compiled =
crate::morphology::io::vector(filters.len()).map_err(super::DictionaryError::from)?;
compiled.extend(filters.iter().map(KoreanFilter::compile));
Ok(Self {
model,
tokenizer,
filters: compiled,
})
}
pub fn analyze(&self, input: &str) -> AnalysisResult<NoriOutput> {
self.analyze_controlled(input, NoriLimits::default(), &mut || Ok(()))
}
pub fn analyze_tokens(&self, input: &str) -> AnalysisResult<crate::AnalyzedText> {
self.analyze_mapped(&crate::FilteredText::new(input))
}
pub fn analyze_mapped(
&self,
input: &crate::FilteredText<'_>,
) -> AnalysisResult<crate::AnalyzedText> {
Ok(self
.analyze_mapped_budgeted(
input,
NoriLimits::default(),
&MemoryBudget::new(usize::MAX),
&mut || Ok(()),
)?
.into_parts()
.0)
}
pub fn analyze_controlled(
&self,
input: &str,
limits: NoriLimits,
poll: &mut impl FnMut() -> AnalysisResult<()>,
) -> AnalysisResult<NoriOutput> {
Ok(self
.analyze_budgeted(input, limits, &MemoryBudget::new(usize::MAX), poll)?
.into_parts()
.0)
}
pub fn analyze_budgeted(
&self,
input: &str,
limits: NoriLimits,
budget: &MemoryBudget,
poll: &mut impl FnMut() -> AnalysisResult<()>,
) -> AnalysisResult<Budgeted<NoriOutput>> {
let mut output = self
.tokenizer
.tokenize_budgeted(input, limits, budget, poll)?;
for filter in &self.filters {
output = filter.apply_budgeted(output, &self.model, limits, poll)?;
}
Ok(output)
}
pub fn analyze_tokens_budgeted(
&self,
input: &str,
limits: NoriLimits,
budget: &MemoryBudget,
poll: &mut impl FnMut() -> AnalysisResult<()>,
) -> AnalysisResult<Budgeted<crate::AnalyzedText>> {
self.analyze_mapped_budgeted(&crate::FilteredText::new(input), limits, budget, poll)
}
pub fn analyze_mapped_budgeted(
&self,
input: &crate::FilteredText<'_>,
limits: NoriLimits,
budget: &MemoryBudget,
poll: &mut impl FnMut() -> AnalysisResult<()>,
) -> AnalysisResult<Budgeted<crate::AnalyzedText>> {
let input = input.clone();
input.prepare_coordinates(budget, poll)?;
let output = self.analyze_budgeted(input.as_str(), limits, budget, poll)?;
crate::AnalyzedText::from_nori_budgeted(output, &input, poll)
}
pub fn normalize(&self, input: &str) -> AnalysisResult<String> {
self.normalize_controlled(input, NoriLimits::default(), &mut || Ok(()))
}
pub fn normalize_controlled(
&self,
input: &str,
limits: NoriLimits,
poll: &mut impl FnMut() -> AnalysisResult<()>,
) -> AnalysisResult<String> {
Ok(self
.normalize_budgeted(input, limits, &MemoryBudget::new(usize::MAX), poll)?
.into_parts()
.0)
}
pub fn normalize_budgeted(
&self,
input: &str,
limits: NoriLimits,
budget: &MemoryBudget,
poll: &mut impl FnMut() -> AnalysisResult<()>,
) -> AnalysisResult<Budgeted<String>> {
filters::normalize_text_budgeted(input, &self.model, limits, budget, poll)
}
pub fn normalize_utf16(
&self,
input: &[u16],
limits: NoriLimits,
poll: &mut impl FnMut() -> AnalysisResult<()>,
) -> AnalysisResult<Vec<u16>> {
Ok(self
.normalize_utf16_budgeted(input, limits, &MemoryBudget::new(usize::MAX), poll)?
.into_parts()
.0)
}
pub fn normalize_utf16_budgeted(
&self,
input: &[u16],
limits: NoriLimits,
budget: &MemoryBudget,
poll: &mut impl FnMut() -> AnalysisResult<()>,
) -> AnalysisResult<Budgeted<Vec<u16>>> {
filters::normalize_budgeted(input, &self.model, limits, budget, poll)
}
}