Accent-insensitive card search
A fold() (lowercase + strip accents, using the same table as nucleo's own normalization) is registered as a SQLite function and used by the name, oracle-text and location filters, so "khazad-dum" finds Troll of Khazad-dûm. The fuzzy name search folds the query too (accented queries used to match nothing) and its exact-name promotion; decklist/ManaBox import falls back to a folded name match; the deck quick filter and tag suggestions fold client-side. Closes #17
This commit is contained in:
42
crates/mtgc-core/src/text.rs
Normal file
42
crates/mtgc-core/src/text.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
//! Accent- and case-insensitive text matching.
|
||||
|
||||
/// Lowercase `s` and strip accents ("Lim-Dûl's Cohort" → "lim-dul's cohort"),
|
||||
/// so typed text matches card names however they're accented. Uses the same
|
||||
/// per-character table as the fuzzy name search's own normalization, so both
|
||||
/// search paths agree on what counts as a match.
|
||||
pub fn fold(s: &str) -> String {
|
||||
s.chars()
|
||||
.map(|c| nucleo::chars::normalize(nucleo::chars::to_lower_case(c)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Register [`fold`] as the SQL function `fold(text)` on `conn`, so queries
|
||||
/// can compare `fold(oc.name)` against a folded pattern.
|
||||
pub(crate) fn register_sql_fold(conn: &rusqlite::Connection) -> rusqlite::Result<()> {
|
||||
use rusqlite::functions::FunctionFlags;
|
||||
conn.create_scalar_function(
|
||||
"fold",
|
||||
1,
|
||||
FunctionFlags::SQLITE_UTF8 | FunctionFlags::SQLITE_DETERMINISTIC,
|
||||
|ctx| {
|
||||
Ok(match ctx.get::<Option<String>>(0)? {
|
||||
Some(s) => Some(fold(&s)),
|
||||
None => None,
|
||||
})
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::fold;
|
||||
|
||||
#[test]
|
||||
fn folds_case_and_accents_and_leaves_ascii_alone() {
|
||||
assert_eq!(fold("Lim-Dûl's Cohort"), "lim-dul's cohort");
|
||||
assert_eq!(fold("Éowyn, Lady of Rohan"), "eowyn, lady of rohan");
|
||||
assert_eq!(fold("Hamato Ninpō"), "hamato ninpo");
|
||||
assert_eq!(fold("Jakub Šlemr"), "jakub slemr");
|
||||
assert_eq!(fold("Lightning Bolt"), "lightning bolt");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user