Skip to main content

uqa_analysis/
porter.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! Porter (1980) stemming algorithm.
8//!
9//! Reference: M. F. Porter, "An Algorithm for Suffix Stripping", *Program*
10//! 14(3), 1980. Note that this is the original 1980 algorithm, not Porter2
11//! (Snowball English) — they differ on edge cases such as `agreed` and
12//! `feedeing`. The output is intentionally identical to the upstream
13//! UQA stemmer contract so that BM25 doc frequencies match across
14//! engines.
15
16mod algorithm;
17mod allocation;
18mod word;
19
20#[cfg(test)]
21pub(crate) use allocation::stem_utf16;
22pub use allocation::{stem, stem_budgeted, stem_term_budgeted};
23
24// Scalars and isolated surrogate units remain distinct algorithm elements.
25#[derive(Clone, Copy, PartialEq, Eq)]
26struct Character(u32);
27
28impl Character {
29    fn is_one_of(self, characters: &[char]) -> bool {
30        characters.iter().any(|&character| self == character)
31    }
32}
33
34impl From<char> for Character {
35    fn from(value: char) -> Self {
36        Self(u32::from(value))
37    }
38}
39
40impl PartialEq<char> for Character {
41    fn eq(&self, other: &char) -> bool {
42        self.0 == u32::from(*other)
43    }
44}
45
46#[cfg(test)]
47mod tests;