Skip to main content

novel_segment/
word.rs

1//! Word token (`IWord` equivalent).
2
3/// A segmented word. Field names match the JavaScript `IWord` object.
4#[derive(Clone, Debug, Default, PartialEq)]
5pub struct Word {
6    /// Word text.
7    pub w: String,
8    /// POS bit flags (`POSTAG`).
9    pub p: Option<u32>,
10    /// Frequency / weight.
11    pub f: Option<f64>,
12    /// Start index in the current section (scalar characters).
13    pub c: Option<usize>,
14    /// Native dictionary entry.
15    pub s: Option<bool>,
16    /// Original word before synonym conversion.
17    pub ow: Option<String>,
18    /// Original POS before conversion / retag.
19    pub op: Option<u32>,
20    /// Merged source tokens (JS `m`).
21    pub m: Option<Vec<Word>>,
22    /// Created by an optimizer and not in TABLE (JS debug `autoCreate`).
23    pub auto_create: bool,
24    /// Previous native-dict flag.
25    pub os: Option<bool>,
26}
27
28impl Word {
29    pub fn new(w: impl Into<String>) -> Self {
30        Self {
31            w: w.into(),
32            ..Default::default()
33        }
34    }
35
36    pub fn with_p(mut self, p: u32) -> Self {
37        self.p = Some(p);
38        self
39    }
40
41    pub fn with_f(mut self, f: f64) -> Self {
42        self.f = Some(f);
43        self
44    }
45
46    pub fn with_c(mut self, c: usize) -> Self {
47        self.c = Some(c);
48        self
49    }
50
51    /// JS `word.p > 0`.
52    pub fn is_recognized(&self) -> bool {
53        self.p.unwrap_or(0) > 0
54    }
55
56    /// JS `typeof word.p === 'number'`.
57    pub fn has_pos(&self) -> bool {
58        self.p.is_some()
59    }
60
61    pub fn pos(&self) -> u32 {
62        self.p.unwrap_or(0)
63    }
64
65    pub fn freq(&self) -> f64 {
66        self.f.unwrap_or(0.0)
67    }
68
69    /// JS `!word.p` — missing or zero POS.
70    pub fn pos_falsy(&self) -> bool {
71        self.p.unwrap_or(0) == 0
72    }
73}
74
75/// Join words back into the original text.
76pub fn stringify(words: &[Word]) -> String {
77    words.iter().map(|w| w.w.as_str()).collect()
78}
79
80/// Join words or strings (for simple mode results stored as words).
81pub fn stringify_list(words: &[Word]) -> Vec<String> {
82    words.iter().map(|w| w.w.clone()).collect()
83}