Profanity filter
Offensive words found and masked in comments, usernames and chat, with l33t spellings and spaced-out letters caught, and a severity per kind for moderation queues.
Version 1.0.0 · 3 functions · 1 crate
Functions
What use profanity.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use profanity_found, profanity_mask from profanity (Quillo 0.6).
profanity_found(text: str) → boolor an errorWhether text holds profane, offensive or sexual words: moderate ones or worse, so "damn" passes and slurs do not. Text up to 200 KB.
profanity_mask(text: str, strictness: str) → stror an errortext with offending words masked by *, most keeping their first letter ("f***"). strictness is "mild" (mask even "damn"), "moderate" or "severe" (mask only the worst).
profanity_analyze(text: str) → anyor an errorHow bad text is, for moderation queues: { inappropriate, profane, offensive, sexual, mean, evasive, spam }, each but the first "none", "mild", "moderate" or "severe". evasive means words disguised to get past filters.
Get it
$ quillo install profanity # profanity.qwer into this folder$ quillo install profanity --example # and its example, profanity.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/profanity.qwer$ curl -O https://quillolang.org/plugins/files/profanity.qweThen, in your program, all of it or only what you call:
use profanity.qweruse profanity_found, profanity_mask from profanity // Quillo 0.6: only theseIt uses this crate, which cargo fetches the first time the plugin is built:
rustrict = { version = "0.7", default-features = false, features = ["censor"] }Example
// Comments masked before they are shown, and a username refused when it is offensive.//// quillo run profanity.qwe then open http://localhost:8080/commentsuse "profanity.qwer"let comments = ["Great post, thanks!", "This is sh1t, you f.u.c.k.i.n.g idiot", "Well, damn, that is clever."]route GET /comments = comments | map((c) => { shown: profanity_mask(c, "moderate")?, flagged: profanity_found(c)? })route GET /username ? { name: str } { if profanity_found(name)? { reply 422 { error: "Please pick another username." } } { ok: name }}route GET /analyze ? { text: str } = profanity_analyze(text)?$ quillo run profanity.qwe$ curl 'localhost:8080/comments'Source
//! Offensive words found and masked in comments, usernames and chat, English, l33t tricks (sh1t, f.u.c.k) and spacing included.//! version: 1.0.0//!//! [dependencies]//! rustrict = { version = "0.7", default-features = false, features = ["censor"] }use rustrict::{Censor, Type};use serde_json::{json, Value};const MAX: usize = 200_000;fn level(t: Type, kind: Type) -> &'static str { if t.is(kind & Type::SEVERE) { "severe" } else if t.is(kind & Type::MODERATE) { "moderate" } else if t.is(kind & Type::MILD) { "mild" } else { "none" }}fn threshold(strictness: &str) -> Result<Type, String> { match strictness { "" | "moderate" => Ok(Type::INAPPROPRIATE & Type::MODERATE_OR_HIGHER), "mild" => Ok(Type::INAPPROPRIATE), "severe" => Ok(Type::INAPPROPRIATE & Type::SEVERE), o => Err(format!("strictness is \"mild\", \"moderate\" or \"severe\", not {:?}", o)), }}/// Whether `text` holds profane, offensive or sexual words: moderate ones or worse, so "damn" passes and slurs do not. Text up to 200 KB.pub fn profanity_found(text: &str) -> Result<bool, String> { if text.len() > MAX { return Err("text up to 200 KB".into()); } Ok(Censor::from_str(text).analyze().is(threshold("")?))}/// `text` with offending words masked by `*`, most keeping their first letter ("f***"). `strictness` is "mild" (mask even "damn"), "moderate" or "severe" (mask only the worst).pub fn profanity_mask(text: &str, strictness: &str) -> Result<String, String> { if text.len() > MAX { return Err("text up to 200 KB".into()); } Ok(Censor::from_str(text).with_censor_threshold(threshold(strictness)?).censor())}/// How bad `text` is, for moderation queues: `{ inappropriate, profane, offensive, sexual, mean, evasive, spam }`, each but the first "none", "mild", "moderate" or "severe". `evasive` means words disguised to get past filters.pub fn profanity_analyze(text: &str) -> Result<Value, String> { if text.len() > MAX { return Err("text up to 200 KB".into()); } let t = Censor::from_str(text).analyze(); Ok(json!({ "inappropriate": t.is(threshold("")?), "profane": level(t, Type::PROFANE), "offensive": level(t, Type::OFFENSIVE), "sexual": level(t, Type::SEXUAL), "mean": level(t, Type::MEAN), "evasive": level(t, Type::EVASIVE), "spam": level(t, Type::SPAM), }))}Related
spam_filter.qwer · 1.0.0A spam filter that learns from your own messages: naive Bayes trained on what users mark, kept in a file, scoring comments and forms from 0 to 1.7 views · 7 downloadsCase case.qwer · 1.0.0Text in snake_case, camelCase, PascalCase, kebab-case, CONSTANT_CASE, Title Case and Sentence case: column names as API keys and labels.7 views · 8 downloadsHumanize humanize.qwer · 1.0.0Durations, file sizes and relative times as people write them and back: 2h 30m, 1.5 GB, 2 GiB, 3 days ago, in 2 hours.7 views · 11 downloadsInflection inflect.qwer · 1.0.0English words in the right form for counts and labels: plurals and singulars, 3 items, ordinals such as 1st and 22nd, and a or an by how a word sounds.6 views · 7 downloadsJapanese kana kana.qwer · 1.0.0Japanese kana: romaji typed as hiragana or katakana, kana written in Hepburn romaji, hiragana and katakana each to the other, half-width katakana from bank and till systems made full-width, and which scripts a text uses.6 views · 10 downloadsSpellcheck 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 downloadsThread 0 posts
On Profanity filter: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.