Documentation
¶
Overview ¶
Package profanity is a fast Go port of the Python better_profanity library (https://github.com/snguyenthanh/better_profanity).
It censors swear words in text, resolving common leetspeak character substitutions (p*ssy, 5h1t, w0rse...) and multi-word phrases ("2 girls 1 cup", "hand job") including variants with separators removed or kept.
Instead of comparing every token against every censor word like the original, it matches tokens against a trie in O(len(token)), which makes it orders of magnitude faster while keeping the exact same semantics.
Index ¶
- func Censor(text string) string
- func ContainsProfanity(text string) bool
- func DefaultWords() []string
- type Option
- type Profanity
- func (p *Profanity) AddCensorWords(words ...string)
- func (p *Profanity) Censor(text string) string
- func (p *Profanity) CensorWith(text string, censorChar rune) string
- func (p *Profanity) ContainsProfanity(text string) bool
- func (p *Profanity) FeedWords(ch <-chan string)
- func (p *Profanity) Len() int
- func (p *Profanity) LoadCensorWords(words []string, opts ...Option)
- func (p *Profanity) LoadCensorWordsFromFile(path string, opts ...Option) error
- func (p *Profanity) LoadDefaultCensorWords(opts ...Option)
- func (p *Profanity) NewWordFeed(buffer int) chan<- string
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Censor ¶
Censor replaces every swear word with "****" using the default word list.
Example ¶
package main
import (
"fmt"
profanity "github.com/roger-russel/go-profanity"
)
func main() {
fmt.Println(profanity.Censor("Holy shit!"))
}
Output: Holy ****!
func ContainsProfanity ¶
ContainsProfanity reports whether text contains any swear word from the default word list.
Example ¶
package main
import (
"fmt"
profanity "github.com/roger-russel/go-profanity"
)
func main() {
fmt.Println(profanity.ContainsProfanity("he is a m0th3rf*cker"))
fmt.Println(profanity.ContainsProfanity("hello world"))
}
Output: true false
func DefaultWords ¶
func DefaultWords() []string
DefaultWords returns a copy of the embedded default censor word list.
Example ¶
package main
import (
"fmt"
profanity "github.com/roger-russel/go-profanity"
)
func main() {
fmt.Println(len(profanity.DefaultWords()))
}
Output: 835
Types ¶
type Option ¶
type Option func(*config)
Option configures New and the Load* methods.
func WithPhoneticNormalization ¶
func WithPhoneticNormalization() Option
WithPhoneticNormalization enables folding of common Portuguese phonetic misspellings (z/s, ph/pf -> f, "aum" -> nasal "ão") so alternate spellings match the same censor word (e.g. "cuzaum", "cusão" match a registered "cuzao"). Disabled by default: it increases the chance of matching unrelated words that happen to share these letters.
func WithSeparatorCollapse ¶
func WithSeparatorCollapse() Option
WithSeparatorCollapse enables collapsing letters that are spelled out one at a time with punctuation between them — e.g. "c.u", "c..u", "a.n.a.l" — so they match the same censor word as "cu"/"anal". Any character that isn't already a word character and isn't whitespace counts as this kind of separator (whitespace keeps its existing phrase-lookahead behavior, e.g. "hand job", untouched). Disabled by default: it increases the chance of matching unrelated punctuation-spaced initials or abbreviations.
func WithWhitelist ¶
WithWhitelist excludes the given words from the censor list.
func WithWordListFile ¶
WithWordListFile makes New load censor words from a file with one word or phrase per line (blank lines are ignored). It is ignored by the Load* methods.
type Profanity ¶
type Profanity struct {
// contains filtered or unexported fields
}
Profanity censors swear words in text. Create it with New; the zero value is usable but censors nothing until words are loaded.
All methods are safe for concurrent use: readers (Censor, CensorWith, ContainsProfanity, Len) never block, and writers (Load*, AddCensorWords, FeedWords) are serialized internally and become visible to subsequent scans atomically. In-flight scans keep the word list they started with.
func New ¶
New returns a Profanity loaded with the default word list, or with the words selected by the given options.
Example (CustomWords) ¶
package main
import (
"fmt"
profanity "github.com/roger-russel/go-profanity"
)
func main() {
p, err := profanity.New(profanity.WithWords("happy", "jolly", "merry"))
if err != nil {
panic(err)
}
fmt.Println(p.Censor("Have a merry day!"))
fmt.Println(p.ContainsProfanity("Fuck you!")) // not in the custom list
}
Output: Have a **** day! false
Example (PhoneticNormalization) ¶
package main
import (
"fmt"
profanity "github.com/roger-russel/go-profanity"
)
func main() {
p, err := profanity.New(
profanity.WithWords("cuzao"),
profanity.WithPhoneticNormalization(),
)
if err != nil {
panic(err)
}
fmt.Println(p.ContainsProfanity("cuzao")) // as registered
fmt.Println(p.ContainsProfanity("cuzaum")) // "aum" folds to "ão"
fmt.Println(p.ContainsProfanity("cusão")) // "s"/"z" fold together
}
Output: true true true
Example (SeparatorCollapse) ¶
package main
import (
"fmt"
profanity "github.com/roger-russel/go-profanity"
)
func main() {
p, err := profanity.New(
profanity.WithWords("cu"),
profanity.WithSeparatorCollapse(),
)
if err != nil {
panic(err)
}
fmt.Println(p.ContainsProfanity("c.u")) // letters spelled out with punctuation
fmt.Println(p.ContainsProfanity("c...u")) // any amount of repeated separator
fmt.Println(p.ContainsProfanity("hello world"))
}
Output: true true false
Example (Whitelist) ¶
package main
import (
"fmt"
profanity "github.com/roger-russel/go-profanity"
)
func main() {
p, err := profanity.New(profanity.WithWhitelist("boobs"))
if err != nil {
panic(err)
}
fmt.Println(p.Censor("I have boobs"))
}
Output: I have boobs
func (*Profanity) AddCensorWords ¶
AddCensorWords adds words to the current censor list. The new words are visible to scans started after it returns.
Example ¶
package main
import (
"fmt"
profanity "github.com/roger-russel/go-profanity"
)
func main() {
p := profanity.MustNew()
p.AddCensorWords("supremacia ariana")
fmt.Println(p.Censor("chega de supremacia ariana"))
}
Output: chega de ****
func (*Profanity) Censor ¶
Censor replaces every swear word in text with "****".
Example ¶
package main
import (
"fmt"
profanity "github.com/roger-russel/go-profanity"
)
func main() {
p := profanity.MustNew()
// Leetspeak variants and multi-word phrases are resolved.
fmt.Println(p.Censor("That wh0re gave m3 a very good H4nd j0b."))
}
Output: That **** gave m3 a very good ****.
func (*Profanity) CensorWith ¶
CensorWith replaces every swear word in text with censorChar repeated four times.
Example ¶
package main
import (
"fmt"
profanity "github.com/roger-russel/go-profanity"
)
func main() {
p := profanity.MustNew()
fmt.Println(p.CensorWith("Holy shit!", '-'))
}
Output: Holy ----!
func (*Profanity) ContainsProfanity ¶
ContainsProfanity reports whether text contains any swear word. It stops at the first match, without building the censored text.
Example ¶
package main
import (
"fmt"
profanity "github.com/roger-russel/go-profanity"
)
func main() {
p := profanity.MustNew()
fmt.Println(p.ContainsProfanity("2 girls 1 cup is my favorite video"))
}
Output: true
func (*Profanity) FeedWords ¶
FeedWords consumes censor words (or phrases) from ch and adds them to the censor list, until ch is closed. It blocks, so run it in its own goroutine:
ch := make(chan string, 64) go p.FeedWords(ch) ch <- "newword" // picked up by scans shortly after
Words already sitting in the channel are drained and applied as a single batch, so bursts cost one snapshot rebuild instead of one per word. Delivery is asynchronous: a word sent to ch becomes active shortly after, but not necessarily before the send returns. When a word must be active before the next scan, call AddCensorWords directly instead — it is also safe for concurrent use.
Example ¶
package main
import (
"fmt"
profanity "github.com/roger-russel/go-profanity"
)
func main() {
p := profanity.MustNew()
ch := make(chan string, 2)
ch <- "blorp"
ch <- "frase proibida"
close(ch)
// FeedWords returns once ch is closed and all pending words are applied.
// In a long-lived program, run it in a goroutine instead:
//
// go p.FeedWords(ch)
p.FeedWords(ch)
fmt.Println(p.Censor("what a blorp day"))
fmt.Println(p.ContainsProfanity("uma frase proibida aqui"))
}
Output: what a **** day true
func (*Profanity) LoadCensorWords ¶
LoadCensorWords replaces the censor list with the given words.
Example ¶
package main
import (
"fmt"
profanity "github.com/roger-russel/go-profanity"
)
func main() {
p := profanity.MustNew()
p.LoadCensorWords([]string{"bobagem"}) // replaces the default list
fmt.Println(p.Censor("que bobagem!"))
fmt.Println(p.ContainsProfanity("Holy shit!"))
}
Output: que ****! false
func (*Profanity) LoadCensorWordsFromFile ¶
LoadCensorWordsFromFile replaces the censor list with the words read from a file with one word or phrase per line.
func (*Profanity) LoadDefaultCensorWords ¶
LoadDefaultCensorWords replaces the censor list with the embedded default word list.
func (*Profanity) NewWordFeed ¶
NewWordFeed starts a background consumer and returns the channel to send new censor words on. Close the channel to stop the consumer; any words already sent are still applied.
Example ¶
package main
import (
profanity "github.com/roger-russel/go-profanity"
)
func main() {
p := profanity.MustNew()
feed := p.NewWordFeed(64)
defer close(feed) // stops the background consumer
// Words become active shortly after being sent, without blocking
// concurrent Censor/ContainsProfanity calls.
feed <- "newbadword"
}
Output: