Skip to content

Replace

Editor.Replace finds a pattern the same way search does, then rewrites the string operands of the text-showing operators behind each match. It is an edit of existing content, not a redraw: the page keeps its original operators, fonts and positioning, and only the bytes inside the strings change. That makes it good for small corrections to text you cannot regenerate, and a poor fit for anything that changes the shape of the text.

Doing it

reader, _, err := model.NewPdfReaderFromFile("input.pdf", nil)
if err != nil {
    return err
}

editor := extractor.NewEditor(reader)

if err := editor.Replace("Australia", "America", []int{1, 2}); err != nil {
    return err
}

if err := editor.WriteToFile("output.pdf"); err != nil {
    return err
}

Nothing is written to disk until WriteToFile, which converts the reader to a writer and saves the whole document, edited pages included. Call Replace as many times as you need first; each call replaces every match of its pattern on the pages given.

Pages whose content changed are re-encoded with a Flate filter, so the output of an edited page will not be byte-identical to the input even where the text is untouched.

Limitations

Length matters. The replacement is handed out across the marks that make up the match, a slice at a time, sized by the text each mark holds. A replacement longer than the pattern is cut off at the pattern’s length, and a shorter one leaves the trailing glyphs of the match empty. Match the length where the exact wording allows it.

Glyph positions are not recalculated. The replacement is drawn with the positioning that was already in the content stream, so a replacement whose glyphs are wider than the original will run into the text after it, and a narrower one leaves a gap. Word spacing set with positioning operators rather than space characters stays where it was.

The replacement is re-encoded with the font the matched text already used, through PdfFont.StringToCharcodeBytes. Characters that font cannot encode are dropped with a debug-level log message and no error, which is the usual reason a replacement comes out with missing letters. A subset-embedded font typically carries only the glyphs the original document used, so replacing “cat” with “dog” can fail on the “g” alone.

Replace reads the page with the default extraction mode because it needs text marks that line up with the extracted text; see text extraction. Text drawn as vector outlines or living inside an image is not text to the extractor and cannot be replaced. The same is true of text in annotations or form field appearances, which are separate streams from the page content.

Replacement is not redaction. The original string is overwritten in the content stream, but nothing else in the file is examined, so a copy of the text elsewhere in the document is left alone. For removing content deliberately, see redaction.

Run the example

replace_text.go takes the pattern, the replacement, the page list, and the input and output paths. It is a thin wrapper: NewEditor, Replace, WriteToFile.

git clone https://github.com/unidoc/unipdf-examples.git
cd unipdf-examples/search-and-replace
go run replace_text.go Australia America 1,2 ./test-data/file1.pdf ./test-data/result.pdf

If this is your first time using UniPDF, follow the getting started guide to create an API key and set up your development environment.

View the full source
Last updated on