use alloc::string::String;
mod emit;
mod fold;
mod normalize;
mod policy;
mod segment;
mod tables;
mod unicode;
pub use self::emit::MAX_TOKEN_BYTES;
pub use self::policy::TokenizerPolicy;
use self::segment::CjkRun;
use self::unicode::UnicodeBackend;
#[derive(Debug, Default, Clone)]
pub struct Tokenizer {
policy: TokenizerPolicy,
norm: String,
token: String,
lower: String,
canonical: String,
unicode: UnicodeBackend,
}
impl Tokenizer {
pub fn new() -> Self {
Self::default()
}
pub fn with_policy(policy: TokenizerPolicy) -> Self {
Self {
policy,
..Self::default()
}
}
pub const fn policy(&self) -> TokenizerPolicy {
self.policy
}
pub fn tokenize(&mut self, text: &str, sink: &mut dyn FnMut(&str)) {
normalize::normalize_into(&self.unicode, text, &mut self.norm);
let policy = self.policy;
let token = &mut self.token;
let lower = &mut self.lower;
let canonical = &mut self.canonical;
let unicode = &self.unicode;
let mut cjk_run = CjkRun::default();
let mut processor =
segment::SegmentProcessor::new(policy, unicode, &mut cjk_run, token, lower, canonical);
let mut start = 0usize;
for end in unicode.word_boundaries(&self.norm) {
if end == start {
continue;
}
let segment = &self.norm[start..end];
if segment.chars().any(char::is_alphanumeric) {
processor.process(segment, sink);
} else {
processor.flush(sink);
}
start = end;
}
processor.flush(sink);
}
}