Redact PDF text with a regular expression in C#
PdfRedactionManager finds content by area, by text or by regular expression and deletes it from the file — text, images, links and form fields underneath are removed, not hidden behind a box.
Compiled and run: Linux ARM64 · Linux x64 · macOS ARM64 · Windows x64
Build it step by step.
-
1Install the NuGet packages
SelectPdf.Universalis the library. The native package carries the Chromium engine for one platform: add the one for the platform you run on.dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.win-x64
dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.linux-x64
dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.linux-arm64
dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.osx-arm64
-
2Create a console app
Any .NET 8 or .NET 10 project works. To follow along, create a console app, run the install commands above inside its folder, then replace
Program.cswith the code below.dotnet new console -n PdfSample cd PdfSample
-
3Import the namespaces
using System.Text.RegularExpressions; using SelectPdf.Universal;
Regexcomes fromSystem.Text.RegularExpressions; everything else is inSelectPdf.Universal. -
4Create a PDF to redact
// 1. Make a statement that contains card numbers. HtmlToPdf converter = new HtmlToPdf(); PdfDocument statement = converter.ConvertHtmlString(""" <h1>Card statement</h1> <p>Primary card: 4111-1111-1111-1111</p> <p>Backup card: 5500-0000-0000-0004</p> """); statement.Save("statement.pdf"); statement.Close();To keep the sample self-contained,
HtmlToPdfconverts a small statement with two card numbers intostatement.pdf. In your application this is the PDF you already have — an upload or a report you generated earlier. -
5Load it into a PdfRedactionManager
// 2. Remove every card number from the file. var redactor = new PdfRedactionManager(); redactor.Load("statement.pdf");PdfRedactionManagerworks on an existing PDF.Loadopens the file you want to clean. -
6Describe what to remove
redactor.AddRedaction(new Regex(@"\d{4}-\d{4}-\d{4}-\d{4}"));AddRedactionwith aRegexmarks every match in the document. The pattern\d{4}-\d{4}-\d{4}-\d{4}matches four groups of four digits separated by dashes — the format of the two card numbers. Adjust it to your data: national IDs, account numbers, e-mail addresses. -
7Mark where content was removed (optional)
redactor.OverlayText = "REDACTED";
OverlayTextwrites a label over each redacted area so readers can see that something was taken out. Leave it unset for a plain box. -
8Apply, save and close
redactor.Redact(); redactor.Save("statement-redacted.pdf"); redactor.Close();Redactapplies all redactions.Savewrites the result to a new file, so the original stays untouched, andClosereleases the document. -
9Run it
dotnet run
The program writes
statement-redacted.pdfto the working folder. Without a license key, every page carries a trial watermark; setGlobalProperties.LicenseKeybefore the first conversion to remove it.
The complete Program.cs.
This is the exact file our samples pipeline compiled and ran on Linux ARM64 and Linux x64 and macOS ARM64 and Windows x64 to produce the output on this page.
using System.Text.RegularExpressions;
using SelectPdf.Universal;
// 1. Make a statement that contains card numbers.
HtmlToPdf converter = new HtmlToPdf();
PdfDocument statement = converter.ConvertHtmlString("""
<h1>Card statement</h1>
<p>Primary card: 4111-1111-1111-1111</p>
<p>Backup card: 5500-0000-0000-0004</p>
""");
statement.Save("statement.pdf");
statement.Close();
// 2. Remove every card number from the file.
var redactor = new PdfRedactionManager();
redactor.Load("statement.pdf");
redactor.AddRedaction(new Regex(@"\d{4}-\d{4}-\d{4}-\d{4}"));
redactor.OverlayText = "REDACTED";
redactor.Redact();
redactor.Save("statement-redacted.pdf");
redactor.Close();
Open the project on GitHub → this program and the variations below, ready to dotnet run
The PDF it produces.
Download statement-redacted.pdf ↓ the file this sample produced, unedited
Variations you will need next.
Each variation is a separate file in the same project, compiled and run with the program above.
Redact a known name or phrase
AddRedaction(text, caseSensitive, wholeWordsOnly) marks every occurrence of an exact text. FillColor changes the box color from the default black. Redact returns a PdfRedactionResult for each area it removed, with the page and the text, which you can write to an audit log.
using SelectPdf.Universal;
static class RedactKnownText
{
public static void Run()
{
HtmlToPdf converter = new HtmlToPdf();
PdfDocument contract = converter.ConvertHtmlString("""
<h1>Supply agreement</h1>
<p>Between Contoso Ltd and Fabrikam Inc.</p>
<p>Contoso Ltd delivers 400 units per month.</p>
""");
contract.Save("contract.pdf");
contract.Close();
var redactor = new PdfRedactionManager();
redactor.Load("contract.pdf");
redactor.FillColor = new PdfColor(128, 128, 128);
// exact text: case-sensitive, whole words only
redactor.AddRedaction("Contoso Ltd", true, true);
// Redact returns what was removed, for an audit log
foreach (PdfRedactionResult r in redactor.Redact())
Console.WriteLine($"page {r.PageIndex + 1}: {r.Text}");
redactor.Save("contract-redacted.pdf");
redactor.Close();
}
}
Redact a fixed area and work in memory
When the position is known, such as a signature box on a fixed form, AddRedaction(pageIndex, rectangle) removes everything inside that rectangle. Coordinates are in points from the top-left corner of the page. Save() without a file name returns the redacted PDF as bytes.
using SelectPdf.Universal;
using SelectPdf.Universal.Drawing;
static class RedactArea
{
public static void Run()
{
HtmlToPdf converter = new HtmlToPdf();
PdfDocument form = converter.ConvertHtmlString("""
<h1>Application form</h1>
<p>Name: Jane Doe</p>
<p>Signature: ____________________</p>
""");
form.Save("form.pdf");
form.Close();
var redactor = new PdfRedactionManager();
redactor.Load("form.pdf");
// a fixed area on page 1 (x, y, width, height in points from the top-left corner)
redactor.AddRedaction(0, new RectangleF(0, 60, 300, 50));
redactor.Redact();
// in memory: Save() returns the redacted PDF as bytes
byte[] pdf = redactor.Save();
redactor.Close();
File.WriteAllBytes("form-redacted.pdf", pdf);
}
}
Common problems and fixes.
The pattern matches nothing
Text is matched as it is stored in the PDF. Test the pattern against the output of the PDF to text converter first. Spacing and line breaks can differ from what you see on screen.
Only some pages should change
Pass page indexes: AddRedaction(regex, new[] { 0, 2 }). Without them the redaction applies to every page and to what the document stores off its pages (properties, bookmarks, annotations, form field text).
The source PDF is password-protected
Use the Load(fileName, password) overload. Load also accepts a stream, a byte array or an open PdfDocument.
Good to know.
- Redaction removes text, images, links and form fields under the redaction from the file; there is nothing left to copy or extract. Source
- Redactions can be found by area, by text or by regular expression, with optional overlay text. Source
- Redaction is part of the commercial SelectPdf.Universal package. Source
Questions, answered.
Short answers about this guide. The SelectPdf.Universal documentation covers every class and option.