Fuzzy search
Rank names against what someone typed, typos and all, edit distances, and did-you-mean.
Version 1.0.0 · 4 functions · 1 crate
Functions
What use fuzzy.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use fuzzy_score, fuzzy_rank from fuzzy (Quillo 0.6).
fuzzy_score(a: str, b: str) → floatHow alike two strings are, 0 to 1, ignoring case: Jaro-Winkler, which favours a shared start.
fuzzy_rank(query: str, items: list, limit: int) → listThe items most like query, best first, as [{ item, score }]: a match at the start or inside an item counts most, then likeness. At most limit, none under 0.5.
edit_distance(a: str, b: str) → intThe edits (insertions, deletions, changes, swaps of neighbours) that turn a into b.
did_you_mean(word: str, items: list, max_edits: int) → str?The item nearest word in edits, for "did you mean ...?", or null when none is within max_edits.
Get it
$ quillo install fuzzy # fuzzy.qwer into this folder$ quillo install fuzzy --example # and its example, fuzzy.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/fuzzy.qwer$ curl -O https://quillolang.org/plugins/files/fuzzy.qweThen, in your program, all of it or only what you call:
use fuzzy.qweruse fuzzy_score, fuzzy_rank from fuzzy // Quillo 0.6: only theseIt uses this crate, which cargo fetches the first time the plugin is built:
strsim = "0.11"Example
// A search box that forgives typos.//// quillo run fuzzy.qwe then open http://localhost:8080/search?q=amsterdmuse "fuzzy.qwer"let cities = ["Amsterdam", "Rotterdam", "Antwerp", "Berlin", "Bern", "Barcelona", "Lisbon", "London"]route GET /search ? { q: str } = fuzzy_rank(q, cities, 3)route GET /mean ? { q: str } = { meant: did_you_mean(q, cities, 2) }$ quillo run fuzzy.qwe$ curl 'localhost:8080/search?q=amsterdm'$ curl 'localhost:8080/mean?q=Lisbn'Source
//! Fuzzy matching: rank names against what someone typed, typos and all, and edit distances.//! version: 1.0.0//!//! [dependencies]//! strsim = "0.11"use serde_json::{json, Value};/// How alike two strings are, 0 to 1, ignoring case: Jaro-Winkler, which favours a shared start.pub fn fuzzy_score(a: &str, b: &str) -> f64 { strsim::jaro_winkler(&a.to_lowercase(), &b.to_lowercase())}/// The `items` most like `query`, best first, as `[{ item, score }]`: a match at the start or inside an item counts most, then likeness. At most `limit`, none under 0.5.pub fn fuzzy_rank(query: &str, items: Vec<String>, limit: i64) -> Vec<Value> { let q = query.to_lowercase(); let mut scored: Vec<(f64, String)> = items.into_iter().map(|it| { let l = it.to_lowercase(); let s = if l.starts_with(&q) { 1.0 } else if l.contains(&q) { 0.9 } else { strsim::jaro_winkler(&q, &l).max(l.split_whitespace().map(|w| strsim::jaro_winkler(&q, w)).fold(0.0, f64::max) * 0.95) }; (s, it) }).filter(|(s, _)| *s >= 0.5).collect(); scored.sort_by(|a, b| b.0.partial_cmp(&a.0).unwrap_or(std::cmp::Ordering::Equal)); scored.into_iter().take(limit.max(0) as usize).map(|(s, it)| json!({ "item": it, "score": (s * 1000.0).round() / 1000.0 })).collect()}/// The edits (insertions, deletions, changes, swaps of neighbours) that turn `a` into `b`.pub fn edit_distance(a: &str, b: &str) -> i64 { strsim::damerau_levenshtein(a, b) as i64}/// The item nearest `word` in edits, for "did you mean ...?", or null when none is within `max_edits`.pub fn did_you_mean(word: &str, items: Vec<String>, max_edits: i64) -> Option<String> { items.into_iter().map(|it| (strsim::damerau_levenshtein(&word.to_lowercase(), &it.to_lowercase()) as i64, it)) .filter(|(d, _)| *d <= max_edits).min_by_key(|(d, _)| *d).map(|(_, it)| it)}Related
spellcheck.qwer · 1.0.0Spelling checked against a word list you load, in any language: unknown words found with their places, suggestions ranked by closeness and frequency (SymSpell's method), text corrected for "did you mean", and your own words added.7 views · 8 downloadsChinese words chinese_segment.qwer · 1.0.0Chinese text split into words for search indexes and counts, with parts of speech, and written in pinyin with tones, tone numbers or initials for sorting and finding names.7 views · 7 downloadsKeywords keywords.qwer · 1.0.0The keywords and key phrases of a text by RAKE, TextRank or TF-IDF, with stop words of 58 languages left out: tags, SEO and related posts.7 views · 6 downloadsN-grams ngrams.qwer · 1.0.0N-grams and shingles: word and character n-grams, the phrases a text uses most, how alike two texts are by shared shingles despite typos, and near-duplicates found among thousands of texts with MinHash.6 views · 9 downloadsPhonetic matching phonetics.qwer · 1.0.0Names matched by how they sound for search and duplicate checks: Soundex, Metaphone, Double Metaphone, NYSIIS, Caverphone and Cologne codes, accents ignored.8 views · 9 downloadsStemming stemming.qwer · 1.0.0Words cut to their stems in 18 languages, so running, runs and run count as one word in a search or a tag cloud.7 views · 8 downloadsThread 0 posts
On Fuzzy search: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.