ComputerysProfanityFilter 1.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package ComputerysProfanityFilter --version 1.0.0
                    
NuGet\Install-Package ComputerysProfanityFilter -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ComputerysProfanityFilter" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ComputerysProfanityFilter" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="ComputerysProfanityFilter" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ComputerysProfanityFilter --version 1.0.0
                    
#r "nuget: ComputerysProfanityFilter, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ComputerysProfanityFilter@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ComputerysProfanityFilter&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=ComputerysProfanityFilter&version=1.0.0
                    
Install as a Cake Tool

ComputerysProfanityFilter

A .NET Standard 2.1 (C# version 9 for unity) profanity filter that censors known terms while recognizing common obfuscations such as character substitutions, punctuation, inserted whitespace, repeated letters, and leetspeak. The default term list is reasonable and covers swears, hate speech, and self-harm.

This library is currently used in STRAFTAT (as of the 1.4.9 update) to filter text chat, player names, lobby names, etc, albeit with a slightly cut down word list (swears removed).

Basic usage

Create one ProfanityList and reuse it when filtering messages. After construction, the instance can be used concurrently from multiple threads. Censor returns the original string unchanged when it finds no match.

using ComputerysProfanityFilter;

ProfanityList profanityFilter = new ProfanityList();
string censored = profanityFilter.Censor("Please don't be an a$$hole.");
// censored: "Please don't be an #######."

Use the optional second argument to choose the replacement character:

string censored = profanityFilter.Censor("Please don't be an a$$hole.", '*');
// censored: "Please don't be an *******."

Matching flexable, case-insensitive, it'll normalizes many substitutions (1337 speak, common enlgish rules), ignores selected punctuation within words, and collapses consecutive repeated letters. Entire matches, including their intervening punctuation, are replaced with the censor character.

Matching flexable, case-insensitive, it'll normalizes many substitutions (1337 speak, common enlgish rules). Punctuation and whitespace may be inserted within terms without preventing a match. Consecutive repeated letters are collapsed, so variants such as foooool can match fool. Matchs are as terms rather than arbitrary substrings, avoiding the Scunthorpe problem, cunt does not match inside Scunthorpe. Recognized punctuation can also act as a boundary between terms. Entire matches, including intervening whitespace and punctuation, are replaced with the censor character.

Detecting profanity

Use HasProfanity when you only need a yes/no result:

bool containsProfanity = filter.HasProfanity("That is a$$hole behavior.");

Use DetectAllProfanities when you need the locations and configured terms that matched:

var matches = filter.DetectAllProfanities("Sh!t happens.");

ProfanityMatch match = matches[0];
// match.Start: 0
// match.End: 4 (exclusive)
// match.Term: "shit"

Start is the zero-based inclusive index in the original input. End is the zero-based exclusive index. A match's Term is the configured term, even when the input uses an expanded or obfuscated form. Matches are returned in source order. Allow terms are excluded from all three operations.

Custom term list

Pass your own terms and normalization rules to the constructor. By default, supplied terms are expanded into several common English forms, so use base terms where appropriate. Set expandTermForms: false to match only the supplied forms after normalization.

using System.Collections.Generic;
using ComputerysProfanityFilter;

ProfanityList filter = new ProfanityList(
    terms: new[] { "spoiler", "example phrase" },
    allowTerms: new[] { "allowed word" },
    expandTermForms: false,
    expectedCharacters: DefaultProfanityList.ExpectedCharacters,
    joinerCharacters: DefaultProfanityList.JoinerCharacters,
    boundaryCharacters: new[] { '.', '-', '_' },
    characterMap: new Dictionary<char, string> { ['4'] = "a", ['@'] = "a" },
    sequenceMap: new Dictionary<string, string>()
);

string censored = filter.Censor("S-p-o-i-l-e-r ahead");
// censored: "############# ahead"

Default configuration

DefaultProfanityList exposes the built-in settings as read-only collections for reuse in custom filters: Terms, AlwaysCensorTerms, AllowTerms, ExpectedCharacters, JoinerCharacters, BoundaryCharacters, CharacterMap, and SequenceMap. Allow terms are compared to the original matched text using lowercase-invariant normalization only.

Allocation behavior

Censor is zero allocate on the heap when no term matches, it'll return the same string instance that was passed in. Only when a match is found will it rent a buffer from ArrayPool<char>.Shared and returns a string that is the same length as the input. The rented buffers can be reused across calls after the pool is warm, although rent may allocate when the pool has no suitable buffer available (and there are some other caveats with ArrayPool, but) Under typical use conditions, it will only allocate a string of the same size input.

Benchmarks

BenchmarkDotNet 0.15.8 results with .NET 10.0.10 on an AMD Ryzen 7 5800X (Windows 11). The suite compares this library with Profanity.Detector 0.1.8 using equivalent vocabularies. Inputs are exactly 100, 1,000, 10,000, or 100,000 characters, made by repeating a fixed 10-message chat corpus containing ordinary, profane, and obfuscated text.

Benchmark run date: August 19, 2026.

Censoring

Results are grouped by vocabulary so each comparison uses the same term list. Times are mean time per Censor operation; allocation is managed allocation per operation.

Expanded default vocabulary (2,578 terms)
Mean Time 100 chars 1,000 chars 10,000 chars 100,000 chars
ComputerysProfanityFilter 2.180 us 25.718 us 254.357 us 2.657 ms
Profanity.Detector 141.017 us 916.118 us 110.825 ms 2.035 s
Managed Allocation 100 chars 1,000 chars 10,000 chars 100,000 chars
ComputerysProfanityFilter - 2 KB 20 KB 195 KB
Profanity.Detector 8 KB 268 KB 64.90 MB 2.23 GB
Profanity.Detector raw vocabulary (1,626 terms)
Mean time 100 chars 1,000 chars 10,000 chars 100,000 chars
ComputerysProfanityFilter 2.676 us 30.427 us 302.885 us 3.151 ms
Profanity.Detector 75.500 us 638.787 us 74.206 ms 1.500 s
Managed Allocation 100 chars 1,000 chars 10,000 chars 100,000 chars
ComputerysProfanityFilter - 2 KB 20 KB 195 KB
Profanity.Detector 5 KB 290 KB 46.96 MB 1.96 GB
CPU-stress input

This benchmark uses a repeated ⚡⚡ input as it was the slowest thing I could find.

Mean Time 100 chars 1,000 chars 10,000 chars 100,000 chars
ComputerysProfanityFilter 4.449 us 41.877 us 415.244 us 4.143 ms
Managed Allocation 100 chars 1,000 chars 10,000 chars 100,000 chars
ComputerysProfanityFilter - - - -

Construction

Construction measurements create one filter instance. This system doesn't have free construction, so be a little bit wary of that. Make sure that you cache your instance after it's created.

Engine and vocabulary Mean Allocated
ComputerysProfanityFilter / expanded default (2,578 terms) 4.656 ms 5.13 MB
Profanity.Detector / same expanded vocabulary (2,578 terms) 6.251 us 33.05 KB
ComputerysProfanityFilter / Profanity.Detector raw vocabulary (1,626 terms) 1.440 ms 2.70 MB
Profanity.Detector / raw default vocabulary (1,626 terms) 5.200 us 25.58 KB

License

Copyright 2026 Christopher Rohland. This project is licensed under the Apache License 2.0. See the LICENSE file for the full license text.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.1

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 40 8/21/2026
1.0.0 48 8/20/2026