pub fn tokenize(text: &str) -> Vec<String> {
text.split(|c: char| !c.is_alphanumeric())
.filter(|t| !t.is_empty())
.map(|t| t.to_lowercase())
.collect()
}
pub fn tokenize_value(value: &serde_json::Value, out: &mut Vec<String>) {
use serde_json::Value;
match value {
Value::String(s) => out.extend(tokenize(s)),
Value::Number(n) => out.extend(tokenize(&n.to_string())),
Value::Bool(b) => out.push(b.to_string()),
Value::Array(a) => a.iter().for_each(|v| tokenize_value(v, out)),
Value::Object(m) => m.values().for_each(|v| tokenize_value(v, out)),
Value::Null => {}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lowercases_and_splits_on_punctuation() {
assert_eq!(tokenize("Rust-lang, 2018!"), vec!["rust", "lang", "2018"]);
}
#[test]
fn numbers_and_arrays_are_searchable() {
let mut out = Vec::new();
tokenize_value(&serde_json::json!({"tags": ["Fast", "Safe"], "year": 2018}), &mut out);
assert!(out.contains(&"fast".to_string()));
assert!(out.contains(&"safe".to_string()));
assert!(out.contains(&"2018".to_string()));
}
}