Skip to content

Profanity filtering identical to better_profanity, up to 12,000× faster

better-profanity-rs gives the same censored text as Python's better_profanity for every input. Checking a 10-word message takes 4 µs instead of 9 ms, and a 700-word article 82 µs instead of 0.9 s. Change the import and keep the rest of your code.

PyPI version crates.io version CI status

Python 3.9+ · wheels for Linux, macOS and Windows

pip install better-profanity-rs

Rust

cargo add better-profanity

Change one import

The profanity object and the Profanity class take the same arguments as in better_profanity 0.7.0 and return the same results:

python
from better_profanity_rs import profanity  # was: from better_profanity import profanity

profanity.censor("This sh1t is expensive, you @ss.")
# 'This **** is expensive, you ****.'
profanity.contains_profanity("sh!t happens")
# True
profanity.load_censor_words(["spoiler", "leak"], whitelist_words=["leak"])
profanity.censor("No spo1ler and no leak, please.", "-")
# 'No ---- and no leak, please.'

load_censor_words_from_file, add_censor_words and the attributes CENSOR_WORDSET, CHARS_MAPPING, MAX_NUMBER_COMBINATIONS and ALLOWED_CHARACTERS work as before.

Speed up code that imports better_profanity

When a library or an app module imports better_profanity itself, call install() first:

python
import better_profanity_rs

better_profanity_rs.install()  # `import better_profanity` now returns better_profanity_rs

import my_web_app

Modules that imported better_profanity before the call keep the original.

How much faster

contains_profanity on windows of Jigsaw toxic comments, median of 20 windows per length. Apple M1 Pro, CPython 3.13; censor gives the same figures.

Wordsbetter_profanitybetter-profanity-rsSpeedup
109.11 ms4.30 µs2,117×
3034.71 ms6.00 µs5,785×
100122.43 ms12.28 µs9,966×
300371.54 ms31.37 µs11,844×
700876.65 ms81.56 µs10,748×

The whole civil_comments test split, 97,320 comments and 5.0 million words, takes 1.10 s. Method and raw results: BENCHMARKS.md.

Why it is so much faster, and still exact

better_profanity keeps its 916 words in a Python list. Every word of the text, alone and joined with the words after it, is compared with each of them by a method that tries the leetspeak variants letter by letter, so a 100-word message costs close to a million comparisons.

Every leetspeak variant is a single character, so a word is a sequence of character sets (a, @, * and 4 for an a). better-profanity-rs stores the list as a trie with character-set edges and runs the original scan, step for step, in Rust: the same word windows, separators, whitelist checks and replacement rules, including the original's quirks.

How "identical" is checked

The tests compare every output and exception with better_profanity 0.7.0 on CPython 3.9 to 3.14: its own test suite, leetspeak words inside texts and joined by separators, custom word lists and whitelists, invalid arguments, attribute changes, subclasses, threads and property-based tests. A separate script compares 313,257 texts, among them the civil_comments test split and the Jigsaw toxic comments, with the default and a custom word list on four Python versions, and a workflow repeats it on Linux, macOS and Windows: no output differs.

For anything the Rust core cannot reproduce exactly, better_profanity's own code, bundled in the package, runs instead, so the output stays the same:

Known differences, such as changes to private attributes of words already in the list, are listed in the README. Free-threaded CPython builds are not supported.

Rust

rust
use better_profanity::Profanity;

let profanity = Profanity::new();
assert_eq!(
    profanity.censor("That wh0re gave m3 a very good H@nD j0b.", "*"),
    "That **** gave m3 a very good ****."
);

let mut custom = Profanity::with_words(["happy", "jolly"]);
custom.add_censor_words(["merry christmas"]);
assert!(custom.contains_profanity("Merry Christmas!"));

The crate lowercases with Rust's Unicode tables; the Python package uses the interpreter's str.lower(), as better_profanity does.

MIT, like better_profanity

pip install better-profanity-rs

Source: github.com/SyntaxSpirits/better-profanity-rs. If any input gives a different result from better_profanity, that is a bug: please open an issue. An independent project, not affiliated with the author of better_profanity.