Masking and anonymizing people's names in text using Go for increased privacy
Or how to use named entity recognition to hide names of people and places before sharing your notes.
I am working on a personal CRM/Note taking app and wanted to show my friends how it works to get some feedback and ideas from them, just in case I consider making it more widely accessible tool or maybe even Open Source. As I was thinking about how to show them, I realized that I didn’t want them to see some of the notes I was taking as they contained information on other people (and possibly about them too ;).
I needed a way to hide or mask the names of people, companies and places in the notes to safely show what I was working on. Since we are dealing with a privacy issue I didn’t want to use a remote AI service provider API and I was a bit too lazy to setup and fiddle with a Local LLM for the task (I have comments about working with Local LLMs as I’ve been experimenting with them for a bit at this point, but that’s for another day).
Here is the quick and dirty solution I cobbled up using Go and the prose library which I have used before for Named Entity Recognition. In the example below we will use an excerpt from a BBC News article which contains several named entities.
Follow these steps to get it running in your environment.
NB: This is a Go program and needs Go to be installed
- Create a new directory and initiate a Go module
mkdir anonymize
cd anonymize
go mod init anonymize
- Create a file named
main.goand place the following contents
package main
import (
"flag"
"fmt"
"strings"
"github.com/go-faker/faker/v4"
"github.com/jdkato/prose/v2"
"github.com/sergi/go-diff/diffmatchpatch"
)
// Source: https://www.bbc.com/news/articles/crr24eqnnq9o
const rawText = `
Using AI to help write code has increased in popularity as the tech becomes more capable and accessible.
Anthropic says it detected a case of so-called "vibe hacking", where its AI was used to write code which could hack into at least 17 different organisations, including government bodies.
It said the hackers "used AI to what we believe is an unprecedented degree".
They used Claude to "make both tactical and strategic decisions, such as deciding which data to exfiltrate, and how to craft psychologically targeted extortion demands".
It even suggested ransom amounts for the victims. Agentic AI - where the tech operates autonomously - has been touted as the next big step in the space. But these examples show some of the risks powerful tools pose to potential victims of cyber-crime. The use of AI means "the time required to exploit cybersecurity vulnerabilities is shrinking rapidly", said Alina Timofeeva, an adviser on cyber-crime and AI.
`
var showDiff = false
func init() {
flag.BoolVar(&showDiff, "diff", false, "Show Diff of the anonymized text")
}
func main() {
flag.Parse()
if showDiff {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(rawText, anonymize(rawText), true)
fmt.Println(dmp.DiffPrettyText(diffs))
} else {
fmt.Println(anonymize(rawText))
}
}
func anonymize(value string) string {
if value == "" {
return value
}
doc, err := prose.NewDocument(value)
if err != nil {
return ""
}
entitiesAsPatterns := make([]string, 0)
for _, ent := range doc.Entities() {
entitiesAsPatterns = append(entitiesAsPatterns, ent.Text)
switch ent.Label {
case "PERSON":
entitiesAsPatterns = append(entitiesAsPatterns, faker.Name())
break
case "LOCATION":
entitiesAsPatterns = append(entitiesAsPatterns, faker.MacAddress())
break
case "FACILITY":
entitiesAsPatterns = append(entitiesAsPatterns, strings.ToUpper(faker.Name()))
break
case "ORGANIZATION":
entitiesAsPatterns = append(entitiesAsPatterns, faker.DomainName())
break
default:
entitiesAsPatterns = append(entitiesAsPatterns, "[MASKED]")
}
}
r := strings.NewReplacer(entitiesAsPatterns...)
return r.Replace(value)
}
Run the program, it has two output modes - by default it will just print the text with the names the Named Entity Recognition algorithm finds replaced with fake names, and in the second mode it prints a diff which shows which text was changed.
Run without diff:
go run main.goRun with DIFF output
go run main.go -diff
The output comes out differently each time so you will most likely get a different result. Here is an example of output from the program.

Here is how it looks with DIFF mode:

Feel free to try with your own text and modify the program to maybe anonymize text from a document or a database. Go crazy!
Caveat The prose library works very well with english but may sometimes miss some entities especially titles or positions, and obviously since the rest of the text is maintained the context of your note could give away information to someone who has more information or context, it’s not a perfect solution!
Conclusion
In this short article we have seen how we can write a simple Go program to help maintain privacy in our notes by masking or anonymizing the original names of people or places in unstructured text. We leverage the prose library to detect entities, the faker library to generate fake data and Go’s standard library strings.Replacer for the heavy lifting and add some diffing to ensure that we can tell what was actually replaced.
NB: I never actually got around to showing my friends the app I am working on 😅 I guess I just needed motivation to write and publish this article.
I hope you found this interesting. Thanks for reading.