Search
extractor.Editor searches the text of chosen pages and reports where each match
sits on the page. Use it when you need coordinates as well as the text: drawing a
highlight or a rectangle over a phrase, or checking whether a document mentions
something before deciding what to do with it. Plain text extraction is enough if
all you want is the string.
Doing it
reader, _, err := model.NewPdfReaderFromFile("input.pdf", nil)
if err != nil {
return err
}
editor := extractor.NewEditor(reader)
matchesPerPage, err := editor.Search("copyright law", []int{1, 2})
if err != nil {
return err
}
for page, match := range matchesPerPage {
for i, box := range match.Locations {
fmt.Printf("page %d %v %v\n", page, match.Indexes[i], box.BBox)
}
}Search takes the page numbers to look at, one-based, and returns
map[int]extractor.Match keyed by page number. A page with no match still gets an
entry, with empty Indexes and Locations, so check the length rather than the
presence of the key.
Match carries the pattern that was searched for, Indexes as [][]int pairs of
start and end byte offsets, and Locations as one Box per match. Box holds a
single field, BBox model.PdfRectangle, so the coordinates are
box.BBox.Llx, Lly, Urx and Ury in PDF units with the origin at the bottom
left of the page.
The pattern is compiled with Go’s regexp package, not matched literally. That
gives you \d, alternation and character classes for free, and it means
characters like ., ( and $ need escaping when you want them literally.
Search returns an error if the pattern does not compile.
Limitations
Offsets in Indexes are byte offsets into the page’s mark text, which is the
paragraph text produced by the default layout extraction mode. They are not
offsets into the string you would get from ExtractText, and they are not rune
indexes. Their only reliable use is as input to TextMarkArray.RangeOffset.
Matching runs one page at a time, so a phrase broken across a page boundary is
never found. Within a page, the text follows the reading order layout mode worked
out, and line breaks appear in it, so a pattern written as a single spaced phrase
can miss text that wraps. Using \s+ in place of a literal space is the usual
fix.
The Editor builds its own extractor internally and always uses the default
extraction mode, so there is no option to search in plain or grid mode. That is
deliberate: search depends on text marks, and only the layout modes produce marks
whose byte offsets line up with the extracted text. See
text extraction for what each mode does.
Run the example
search_text.go searches one pattern across a comma-separated page list and
prints the offsets and boxes. printSearchResults is the formatting helper; the
search itself is three calls in main.
git clone https://github.com/unidoc/unipdf-examples.git
cd unipdf-examples/search-and-replace
go run search_text.go copyright 1,2 ./test-data/file1.pdfIf this is your first time using UniPDF, follow the getting started guide to create an API key and set up your development environment.
Quote the pattern if it contains spaces or shell metacharacters:
go run search_text.go "copyright law" 1,2 ./test-data/file1.pdfView the full source
Sample output
Page 1:
indexes: [292:305]
locations: {307.08 469.42 362.53 479.42}
Page 2:
indexes: [2459:2472], [2785:2798]
locations: {128.93 231.18 184.54 241.18}, {103.11 183.18 158.88 193.18}