use std::collections::BTreeMap;
use std::rc::Rc;
use crate::config::Config;
use crate::error::Result;
use crate::formula::impls::WienerSachtextformel;
use crate::formula::{registry, FormulaRegistry, FormulaResult};
use crate::hyphenation::{parse_tex, LiangHyphenator};
use crate::language::{JsonLanguageRepository, Language};
use crate::syllable::{
CompositeSyllableCounter, HeuristicSyllableCounter, SyllableCounterKind, TexSyllableCounter,
};
use crate::text::{TextAnalyzer, TextSplitter, TextStatistics};
pub struct ReadSight {
language: Rc<Language>,
analyzer: TextAnalyzer,
registry: FormulaRegistry,
}
impl ReadSight {
pub fn new(language: &str) -> Result<Self> {
Self::with_config(language, Config::default_embedded())
}
pub fn with_config(language: &str, config: Config) -> Result<Self> {
let mut repository = JsonLanguageRepository::new(config.clone());
let language = Rc::new(repository.find(language)?.clone());
let tex_contents = config.read_pattern(&language.code)?;
let loaded = parse_tex(&tex_contents);
let hyphenator = Rc::new(LiangHyphenator::new(
loaded.patterns,
loaded.exceptions,
language.min_hyphen_left,
language.min_hyphen_right,
));
let syllable_counter = Self::load_syllable_counter(&language, &hyphenator);
let splitter = TextSplitter::new(&language)?;
let analyzer = TextAnalyzer::new(
Rc::clone(&hyphenator),
syllable_counter,
splitter,
Rc::clone(&language),
);
let registry = registry::create();
Ok(ReadSight {
language,
analyzer,
registry,
})
}
fn load_syllable_counter(
language: &Language,
hyphenator: &Rc<LiangHyphenator>,
) -> SyllableCounterKind {
let mode = language.syllable_mode.as_str();
if mode == "tex" || language.syllable_heuristics.is_none() {
return SyllableCounterKind::Tex(TexSyllableCounter::new(Rc::clone(hyphenator)));
}
let heuristic = HeuristicSyllableCounter::new(language.syllable_heuristics.as_ref());
if mode == "heuristic" {
return SyllableCounterKind::Heuristic(heuristic);
}
SyllableCounterKind::Composite(CompositeSyllableCounter::new(
heuristic,
TexSyllableCounter::new(Rc::clone(hyphenator)),
))
}
pub fn supported_languages(config: Option<&Config>) -> Vec<String> {
let owned;
let config = match config {
Some(c) => c,
None => {
owned = Config::default_embedded();
&owned
}
};
JsonLanguageRepository::new(config.clone())
.list_codes()
.unwrap_or_default()
}
pub fn language(&self) -> &Language {
&self.language
}
pub fn supported_formulas(&self) -> Vec<String> {
self.registry.list_for_language(&self.language)
}
pub fn registry(&self) -> &FormulaRegistry {
&self.registry
}
pub fn split_word(&self, word: &str) -> Vec<String> {
self.analyzer.split_word(word)
}
pub fn split_syllables(&self, word: &str) -> Vec<String> {
self.analyzer.split_syllables(word)
}
pub fn syllable_count(&self, word: &str) -> i64 {
self.analyzer.syllable_count(word)
}
pub fn word_count(&self, text: &str) -> i64 {
self.analyzer.word_count(text)
}
pub fn sentence_count(&self, text: &str) -> i64 {
self.analyzer.sentence_count(text)
}
pub fn letter_count(&self, text: &str) -> i64 {
self.analyzer.letter_count(text)
}
pub fn total_syllables(&self, text: &str) -> i64 {
self.analyzer.total_syllables(text)
}
pub fn average_syllables_per_word(&self, text: &str) -> f64 {
self.analyzer.average_syllables_per_word(text)
}
pub fn average_words_per_sentence(&self, text: &str) -> f64 {
self.analyzer.average_words_per_sentence(text)
}
pub fn polysyllable_count(&self, text: &str, count_proper_nouns: bool) -> i64 {
self.analyzer.polysyllable_count(text, count_proper_nouns)
}
pub fn words_with_more_than_n_syllables(
&self,
text: &str,
n: i64,
count_proper_nouns: bool,
) -> i64 {
self.analyzer
.words_with_more_than_n_syllables(text, n, count_proper_nouns)
}
pub fn histogram_syllables(&self, text: &str) -> BTreeMap<i64, i64> {
self.analyzer.histogram_syllables(text)
}
pub fn analyze(&self, text: &str) -> Result<TextStatistics> {
self.analyzer.analyze(text)
}
pub fn add_hyphenations<I, K, V>(&self, hyphenations: I)
where
I: IntoIterator<Item = (K, V)>,
K: AsRef<str>,
V: AsRef<str>,
{
self.analyzer.add_hyphenations(hyphenations);
}
pub fn score(&self, formula_name: &str, text: &str) -> Result<FormulaResult> {
let stats = self.analyze(text)?;
self.registry
.calculate(formula_name, &self.language, &stats)
}
pub fn flesch_reading_ease(&self, text: &str) -> Result<FormulaResult> {
self.score("flesch_reading_ease", text)
}
pub fn flesch_kincaid_grade_level(&self, text: &str) -> Result<FormulaResult> {
self.score("flesch_kincaid_grade_level", text)
}
pub fn gunning_fog(&self, text: &str) -> Result<FormulaResult> {
self.score("gunning_fog", text)
}
pub fn smog_index(&self, text: &str) -> Result<FormulaResult> {
self.score("smog", text)
}
pub fn coleman_liau(&self, text: &str) -> Result<FormulaResult> {
self.score("coleman_liau", text)
}
pub fn automated_readability_index(&self, text: &str) -> Result<FormulaResult> {
self.score("ari", text)
}
pub fn lix(&self, text: &str) -> Result<FormulaResult> {
self.score("lix", text)
}
pub fn gulpease(&self, text: &str) -> Result<FormulaResult> {
self.score("gulpease", text)
}
pub fn fernandez_huerta(&self, text: &str) -> Result<FormulaResult> {
self.score("fernandez_huerta", text)
}
pub fn szigriszt_pazos(&self, text: &str) -> Result<FormulaResult> {
self.score("szigriszt_pazos", text)
}
pub fn gutierrez_polini(&self, text: &str) -> Result<FormulaResult> {
self.score("gutierrez_polini", text)
}
pub fn crawford(&self, text: &str) -> Result<FormulaResult> {
self.score("crawford", text)
}
pub fn fog_pl(&self, text: &str) -> Result<FormulaResult> {
self.score("fog_pl", text)
}
pub fn dale_chall(&self, text: &str) -> Result<FormulaResult> {
self.score("dale_chall", text)
}
pub fn spache(&self, text: &str) -> Result<FormulaResult> {
self.score("spache", text)
}
pub fn osman(&self, text: &str) -> Result<FormulaResult> {
self.score("osman", text)
}
pub fn wiener_sachtextformel(&self, text: &str, variant: i32) -> Result<FormulaResult> {
let stats = self.analyze(text)?;
WienerSachtextformel.calculate_variant(&stats, &self.language, variant)
}
}