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