> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/core/get-started/samples/textsearchtest.md).

# Search PDF for Text / String - TextSearch

Sample code for using Apryse SDK to search text on PDF pages using regular expressions. The TextSearch utility class builds on functionality available in TextExtractor to simplify most common search o

Sample code for using Apryse SDK to search text on PDF pages using regular expressions; provided in Python, C++, C#, Java, Node.js (JavaScript), PHP, Ruby, Go and VB. The TextSearch utility class builds on functionality available in [TextExtractor Sample](/core/get-started/samples/textextracttest.md) to simplify most common search operations. Learn more about our [Server SDK](/core/get-started/get-started.md) and [PDF Indexed Search Library](/core/search/search.md).

{% tabs %}
{% tab title="C#" %}
{% code lineNumbers="true" %}

```csharp
//
// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
//

using System;
using pdftron;
using pdftron.Common;
using pdftron.Filters;
using pdftron.SDF;
using pdftron.PDF;


namespace TextSearchTestCS
{
	// This sample illustrates various text search capabilities of PDFNet.

	class Class1
	{		
		private static pdftron.PDFNetLoader pdfNetLoader = pdftron.PDFNetLoader.Instance();
		static Class1() {}
		
		static void Main(string[] args)
		{
			PDFNet.Initialize(PDFTronLicense.Key);

			// Relative path to the folder containing test files.
			string input_path =  "../../../../TestFiles/";

			// Sample code showing how to use high-level text extraction APIs.
			try	
			{
				using (PDFDoc doc = new PDFDoc(input_path + "credit card numbers.pdf"))
				{
					doc.InitSecurityHandler();

					Int32 page_num = 0;
					String result_str = "", ambient_string = "";
					Highlights hlts = new Highlights();

					TextSearch txt_search = new TextSearch();
					Int32 mode = (Int32)(TextSearch.SearchMode.e_whole_word | TextSearch.SearchMode.e_page_stop | TextSearch.SearchMode.e_highlight);
					String pattern = "joHn sMiTh";

					//call Begin() method to initialize the text search.
					txt_search.Begin( doc, pattern, mode, -1, -1 );

					int step = 0;
			
					//call Run() method iteratively to find all matching instances.
					while ( true )
					{
						TextSearch.ResultCode code = txt_search.Run(ref page_num, ref result_str, ref ambient_string, hlts );

						if ( code == TextSearch.ResultCode.e_found )
						{
							if ( step == 0 )
							{	//step 0: found "John Smith"
								//note that, here, 'ambient_string' and 'hlts' are not written to, 
								//as 'e_ambient_string' and 'e_highlight' are not set.
								Console.WriteLine(result_str + "'s credit card number is: ");

								//now switch to using regular expressions to find John's credit card number
								mode = txt_search.GetMode();
								mode |= (Int32)(TextSearch.SearchMode.e_reg_expression | TextSearch.SearchMode.e_highlight);
								txt_search.SetMode(mode);
								pattern = "\\d{4}-\\d{4}-\\d{4}-\\d{4}"; //or "(\\d{4}-){3}\\d{4}"
								txt_search.SetPattern(pattern);

								++step;
							}
							else if ( step == 1 )
							{
								//step 1: found John's credit card number
								//result_str.ConvertToAscii(char_buf, 32, true);
								//cout << "  " << char_buf << endl;
								Console.WriteLine("  " + result_str);

								//note that, here, 'hlts' is written to, as 'e_highlight' has been set.
								//output the highlight info of the credit card number
								hlts.Begin(doc);
								while (hlts.HasNext())
								{
									Console.WriteLine("The current highlight is from page: " + hlts.GetCurrentPageNumber());
									hlts.Next();
								}

								//see if there is an AMEX card number
								pattern = "\\d{4}-\\d{6}-\\d{5}";
								txt_search.SetPattern(pattern);

								++step;
							}
							else if ( step == 2 )
							{
								//found an AMEX card number
								Console.WriteLine("\nThere is an AMEX card number:\n  " + result_str);

								//change mode to find the owner of the credit card; supposedly, the owner's
								//name proceeds the number
								mode = txt_search.GetMode();
								mode |= (Int32)(TextSearch.SearchMode.e_search_up);
								txt_search.SetMode(mode);
								pattern = "[A-z]++ [A-z]++";
								txt_search.SetPattern(pattern);

								++step;
							}
							else if ( step == 3 )
							{
								//found the owner's name of the AMEX card
								Console.WriteLine("Is the owner's name:\n  " + result_str + "?");

								//add a link annotation based on the location of the found instance
								hlts.Begin(doc);
								while (hlts.HasNext())
								{
									Page cur_page = doc.GetPage(hlts.GetCurrentPageNumber());
									double[] quads = hlts.GetCurrentQuads();
									int quad_count = quads.Length / 8;
									for (int i = 0; i < quad_count; ++i)
									{
										//assume each quad is an axis-aligned rectangle
										int offset = 8 * i;
										double x1 = Math.Min(Math.Min(Math.Min(quads[offset + 0], quads[offset + 2]), quads[offset + 4]), quads[offset + 6]);
										double x2 = Math.Max(Math.Max(Math.Max(quads[offset + 0], quads[offset + 2]), quads[offset + 4]), quads[offset + 6]);
										double y1 = Math.Min(Math.Min(Math.Min(quads[offset + 1], quads[offset + 3]), quads[offset + 5]), quads[offset + 7]);
										double y2 = Math.Max(Math.Max(Math.Max(quads[offset + 1], quads[offset + 3]), quads[offset + 5]), quads[offset + 7]);

										pdftron.PDF.Annots.Link hyper_link = pdftron.PDF.Annots.Link.Create(doc, new Rect(x1, y1, x2, y2), pdftron.PDF.Action.CreateURI(doc, "http://www.pdftron.com"));
										hyper_link.RefreshAppearance();
										cur_page.AnnotPushBack(hyper_link);
									}
									hlts.Next();
								}
								string output_path = "../../../../TestFiles/Output/";
								doc.Save(output_path + "credit card numbers_linked.pdf", SDFDoc.SaveOptions.e_linearized);

								break;
							}
						}
						else if ( code == TextSearch.ResultCode.e_page )
						{
							//you can update your UI here, if needed
						}
						else
						{
							break;
						}
					}
				}
			}

			catch (PDFNetException e)
			{
				Console.WriteLine(e.Message);
			}
			PDFNet.Terminate();
		}
	}
}
```

{% endcode %}
{% endtab %}

{% tab title="C++" %}
{% code lineNumbers="true" %}

```cpp
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

// This sample shows how to use pdftron.PDF.TextSearch to search text on PDF pages
// using regular expressions. TextSearch utility class builds on functionality 
// available in TextExtractor to simplify most common search operations.

#include <PDF/PDFNet.h>
#include <PDF/PDFDoc.h>
#include <PDF/TextSearch.h>
#include <PDF/Annot.h>
#include <iostream>
#include "../../LicenseKey/CPP/LicenseKey.h"

using namespace std;
using namespace pdftron;
using namespace PDF;
using namespace SDF;
using namespace Common;

#undef max
#undef min
#include <algorithm>

int main(int argc, char *argv[])
{
	int ret = 0;
	PDFNet::Initialize(LicenseKey);
	std::string input_path =  "../../TestFiles/credit card numbers.pdf";
	const char* filein = argc>1 ? argv[1] : input_path.c_str();

	try
	{
		PDFDoc doc(filein);
		doc.InitSecurityHandler();

		TextSearch txt_search;
		TextSearch::Mode mode = TextSearch::e_whole_word | TextSearch::e_page_stop;
		UString pattern( "joHn sMiTh" );

		//call Begin() method to initialize the text search.
		txt_search.Begin( doc, pattern, mode );

		int step = 0;
	
		//call Run() method iteratively to find all matching instances.
		while ( true )
		{
			SearchResult result = txt_search.Run();

			if ( result )
			{
				if ( step == 0 )
				{	// Step 0: found "John Smith"
					// note that, here, 'ambient_string' and 'hlts' are not written to, 
					// as 'e_ambient_string' and 'e_highlight' are not set.

					cout << result.GetMatch() << "'s credit card number is: " << endl;

					//now switch to using regular expressions to find John's credit card number
					mode = txt_search.GetMode();
					mode |= TextSearch::e_reg_expression | TextSearch::e_highlight;
					txt_search.SetMode(mode);
					pattern = "\\d{4}-\\d{4}-\\d{4}-\\d{4}"; //or "(\\d{4}-){3}\\d{4}"
					txt_search.SetPattern(pattern);

					++step;
				}
				else if ( step == 1 )
				{
					//step 1: found John's credit card number
					cout << "  " << result.GetMatch() << endl;

					//note that, here, 'hlts' is written to, as 'e_highlight' has been set.
					//output the highlight info of the credit card number.
					Highlights hlts = result.GetHighlights();
					hlts.Begin(doc);
					while ( hlts.HasNext() )
					{
						cout << "The current highlight is from page: " << hlts.GetCurrentPageNumber() << endl;
						hlts.Next();
					}

					//see if there is an AMEX card number
					pattern = "\\d{4}-\\d{6}-\\d{5}";
					txt_search.SetPattern(pattern);

					++step;
				}
				else if ( step == 2 )
				{
					//found an AMEX card number
					cout << "\nThere is an AMEX card number:\n  " << result.GetMatch() << endl;

					//change mode to find the owner of the credit card; supposedly, the owner's
					//name proceeds the number
					mode = txt_search.GetMode();
					mode |= TextSearch::e_search_up;
					txt_search.SetMode(mode);
					pattern = "[A-z]++ [A-z]++";
					txt_search.SetPattern(pattern);

					++step;
				}
				else if ( step == 3 )
				{
					//found the owner's name of the AMEX card
					cout << "Is the owner's name:\n  " << result.GetMatch() << "?\n" << flush;

					//add a link annotation based on the location of the found instance
					Highlights hlts = result.GetHighlights();
					hlts.Begin(doc);
					while ( hlts.HasNext() )
					{
						Page cur_page= doc.GetPage(hlts.GetCurrentPageNumber());
						const double *quads;
						int quad_count = hlts.GetCurrentQuads(quads);
						for ( int i = 0; i < quad_count; ++i )
						{
							//assume each quad is an axis-aligned rectangle
							const double *q = &quads[8*i];
							double x1 = min(min(min(q[0], q[2]), q[4]), q[6]);
							double x2 = max(max(max(q[0], q[2]), q[4]), q[6]);
							double y1 = min(min(min(q[1], q[3]), q[5]), q[7]);
							double y2 = max(max(max(q[1], q[3]), q[5]), q[7]);
							Annots::Link hyper_link = Annots::Link::Create(doc, Rect(x1, y1, x2, y2), Action::CreateURI(doc, "http://www.pdftron.com"));
							cur_page.AnnotPushBack(hyper_link);
						}
						hlts.Next();
					}
					std::string output_path = "../../TestFiles/Output/";
					doc.Save((output_path + "credit card numbers_linked.pdf").c_str(), SDFDoc::e_linearized, 0);
					break;
				}
			}
			else if ( result.IsPageEnd() )
			{
				//you can update your UI here, if needed
			}
			else  
			{
				assert (result.IsDocEnd());
				break;
			}
		}
	}
	catch(Exception& e)
	{
		cout << e << endl;
		ret = 1;
	}
	catch(...)
	{
		cout << "Unknown Exception" << endl;
		ret = 1;
	}

	PDFNet::Terminate();
	return ret;
}
```

{% endcode %}
{% endtab %}

{% tab title="Go" %}
{% code lineNumbers="true" %}

```go
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2021 by PDFTron Systems Inc. All Rights Reserved.
// Consult LICENSE.txt regarding license information.
//---------------------------------------------------------------------------------------

package main
import (
	"fmt"
	"strconv"
	. "math"
	. "pdftron"
)

import  "pdftron/Samples/LicenseKey/GO"

// This sample illustrates the basic text search capabilities of PDFNet.

// Relative path to the folder containing the test files.
var inputPath = "../../TestFiles/"
var outputPath = "../../TestFiles/Output/"

func main(){
    // Initialize PDFNet
    PDFNetInitialize(PDFTronLicense.Key)
    doc := NewPDFDoc(inputPath + "credit card numbers.pdf")
    doc.InitSecurityHandler()
    
    txtSearch := NewTextSearch()
    mode := TextSearchE_whole_word | TextSearchE_page_stop
    
    pattern := "joHn sMiTh"
    
    // call Begin() method to initialize the text search.
    txtSearch.Begin(doc, pattern, uint(mode))

    step := 0
    
    // call Run() method iteratively to find all matching instances.
    for true{
        searchResult := txtSearch.Run()
        if searchResult.IsFound(){
            if step == 0{
                // step 0: found "John Smith"
                // note that, here, 'ambient_string' and 'hlts' are not written to, 
                // as 'e_ambient_string' and 'e_highlight' are not set.
                
                fmt.Println(searchResult.GetMatch() + "'s credit card number is: ")
                // now switch to using regular expressions to find John's credit card number
                mode := PdftronPDFTextSearchTextSearchModes(txtSearch.GetMode())
                mode = mode | TextSearchE_reg_expression | TextSearchE_highlight
                txtSearch.SetMode(uint(mode))
                pattern := "\\d{4}-\\d{4}-\\d{4}-\\d{4}"     //or "(\\d{4}-){3}\\d{4}"
                txtSearch.SetPattern(pattern)
                step = step + 1
            }else if step == 1{
                // step 1: found John's credit card number
                fmt.Println("  " + searchResult.GetMatch())
                
                // note that, here, 'hlts' is written to, as 'e_highligh' has been set.
                // output the highlight info of the credit card number
                hlts := searchResult.GetHighlights()
                hlts.Begin(doc)
                for hlts.HasNext(){
                    fmt.Println("The current highlight is from page: " + strconv.Itoa(hlts.GetCurrentPageNumber()))
                    hlts.Next()
                }
                // see if there is an AMEX card number
                pattern := "\\d{4}-\\d{6}-\\d{5}"
                txtSearch.SetPattern(pattern)
                
                step = step + 1
            }else if step == 2{
                // found an AMEX card number
                fmt.Println("\nThere is an AMEX card number:\n  " + searchResult.GetMatch())
                
                // change mode to find the owner of the credit card; supposedly, the owner's
                // name proceeds the number
                mode := PdftronPDFTextSearchTextSearchModes(txtSearch.GetMode())
                mode = mode | TextSearchE_search_up
                txtSearch.SetMode(uint(mode))
                pattern := "[A-z]++ [A-z]++"
                txtSearch.SetPattern(pattern)
                step = step + 1
            }else if step == 3{
                // found the owner's name of the AMEX card
                fmt.Println("Is the owner's name:\n  " + searchResult.GetMatch() + "?")
                
                // add a link annotation based on the location of the found instance
                hlts := searchResult.GetHighlights()
                hlts.Begin(doc)
                
                for hlts.HasNext(){
                    curPage := doc.GetPage(uint(hlts.GetCurrentPageNumber()))
                    quadsInfo := hlts.GetCurrentQuads()
                    
                    i := 0
                    for i < int(quadsInfo.Size()){
                        q := quadsInfo.Get(i)
                        // assume each quad is an axis-aligned rectangle 
                        x1 := Min(Min(Min(q.GetP1().GetX(), q.GetP2().GetX()), q.GetP3().GetX()), q.GetP4().GetX())
                        x2 := Max(Max(Max(q.GetP1().GetX(), q.GetP2().GetX()), q.GetP3().GetX()), q.GetP4().GetX())
                        y1 := Min(Min(Min(q.GetP1().GetY(), q.GetP2().GetY()), q.GetP3().GetY()), q.GetP4().GetY())
                        y2 := Max(Max(Max(q.GetP1().GetY(), q.GetP2().GetY()), q.GetP3().GetY()), q.GetP4().GetY())
                        hyperLink := LinkCreate(doc.GetSDFDoc(), NewRect(x1, y1, x2, y2), ActionCreateURI(doc.GetSDFDoc(), "http://www.pdftron.com"))
                        curPage.AnnotPushBack(hyperLink)
                        i = i + 1
					}
                    hlts.Next()
				}
                doc.Save(outputPath + "credit card numbers_linked.pdf", uint(SDFDocE_linearized))
                break
			}
        }else if searchResult.IsPageEnd(){
            //you can update your UI here, if needed
        }else{
            break
		}
    }    
    doc.Close()
    PDFNetTerminate()
}
```

{% endcode %}
{% endtab %}

{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

import com.pdftron.common.PDFNetException;
import com.pdftron.pdf.*;
import com.pdftron.sdf.SDFDoc;

// This sample illustrates the basic text search capabilities of PDFNet.
public class TextSearchTest {

    public static void main(String[] args) {
        PDFNet.initialize(PDFTronLicense.Key());
        String input_path = "../../TestFiles/";

        try (PDFDoc doc = new PDFDoc(input_path + "credit card numbers.pdf")) {
            doc.initSecurityHandler();

            TextSearch txt_search = new TextSearch();
            int mode = TextSearch.e_whole_word | TextSearch.e_page_stop;

            String pattern = "joHn sMiTh";

            //PDFDoc doesn't allow simultaneous access from different threads. If this
            //document could be used from other threads (e.g., the rendering thread inside
            //PDFView/PDFViewCtrl, if used), it is good practice to lock it.
            //Notice: don't forget to call doc.Unlock() to avoid deadlock.
            doc.lock();

            //call Begin() method to initialize the text search.
            txt_search.begin(doc, pattern, mode, -1, -1);

            int step = 0;

            //call Run() method iteratively to find all matching instances.
            while (true) {
                TextSearchResult result = txt_search.run();

                if (result.getCode() == TextSearchResult.e_found) {
                    if (step == 0) {
                        //step 0: found "John Smith"
                        //note that, here, 'ambient_string' and 'hlts' are not written to,
                        //as 'e_ambient_string' and 'e_highlight' are not set.
                        System.out.println(result.getResultStr() + "'s credit card number is: ");

                        //now switch to using regular expressions to find John's credit card number
                        mode = txt_search.getMode();
                        mode |= TextSearch.e_reg_expression | TextSearch.e_highlight;
                        txt_search.setMode(mode);
                        String new_pattern = "\\d{4}-\\d{4}-\\d{4}-\\d{4}"; //or "(\\d{4}-){3}\\d{4}"
                        txt_search.setPattern(new_pattern);

                        step = step + 1;
                    } else if (step == 1) {
                        //step 1: found John's credit card number
                        System.out.println("  " + result.getResultStr());

                        //note that, here, 'hlts' is written to, as 'e_highlight' has been set.
                        //output the highlight info of the credit card number
                        Highlights hlts = result.getHighlights();
                        hlts.begin(doc);
                        while (hlts.hasNext()) {
                            System.out.println("The current highlight is from page: " + hlts.getCurrentPageNumber());
                            hlts.next();
                        }

                        //see if there is an AMEX card number
                        String new_pattern = "\\d{4}-\\d{6}-\\d{5}";
                        txt_search.setPattern(new_pattern);

                        step = step + 1;
                    } else if (step == 2) {
                        //found an AMEX card number
                        System.out.println("\nThere is an AMEX card number:");
                        System.out.println("  " + result.getResultStr());

                        //change mode to find the owner of the credit card; supposedly, the owner's
                        //name proceeds the number
                        mode = txt_search.getMode();
                        mode |= TextSearch.e_search_up;
                        txt_search.setMode(mode);
                        String new_pattern = "[A-z]++ [A-z]++";
                        txt_search.setPattern(new_pattern);

                        step = step + 1;
                    } else if (step == 3) {
                        //found the owner's name of the AMEX card
                        System.out.println("Is the owner's name:");
                        System.out.println("  " + result.getResultStr() + "?");

                        //add a link annotation based on the location of the found instance
                        Highlights hlts = result.getHighlights();
                        hlts.begin(doc);
                        while (hlts.hasNext()) {
                            Page cur_page = doc.getPage(hlts.getCurrentPageNumber());
                            double[] q = hlts.getCurrentQuads();
                            int quad_count = q.length / 8;
                            for (int i = 0; i < quad_count; ++i) {
                                //assume each quad is an axis-aligned rectangle
                                int offset = 8 * i;
                                double x1 = Math.min(Math.min(Math.min(q[offset + 0], q[offset + 2]), q[offset + 4]), q[offset + 6]);
                                double x2 = Math.max(Math.max(Math.max(q[offset + 0], q[offset + 2]), q[offset + 4]), q[offset + 6]);
                                double y1 = Math.min(Math.min(Math.min(q[offset + 1], q[offset + 3]), q[offset + 5]), q[offset + 7]);
                                double y2 = Math.max(Math.max(Math.max(q[offset + 1], q[offset + 3]), q[offset + 5]), q[offset + 7]);
                                com.pdftron.pdf.annots.Link hyper_link = com.pdftron.pdf.annots.Link.create(doc, new Rect(x1, y1, x2, y2), Action.createURI(doc, "http://www.pdftron.com"));
                                cur_page.annotPushBack(hyper_link);
                            }
                            hlts.next();
                        }
                        String output_path = "../../TestFiles/Output/";
                        doc.save(output_path + "credit card numbers_linked.pdf", SDFDoc.SaveMode.LINEARIZED, null);
                        // output PDF doc
                        break;
                    }
                } else if (result.getCode() == TextSearchResult.e_page) {
                    //you can update your UI here, if needed
                } else {
                    break;
                }
            }

            doc.unlock();
        } catch (PDFNetException e) {
            System.out.println(e);
        }

        PDFNet.terminate();
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="JavaScript" %}
{% code lineNumbers="true" %}

```js
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------


const { PDFNet } = require('@pdftron/pdfnet-node');
const PDFTronLicense = require('../LicenseKey/LicenseKey');

((exports) => {

  exports.runTextSearchTest = () => {

    const main = async() => {
      // Relative path to the folder containing test files.
      const inputURL = '../TestFiles/';
      const inputFilename = 'credit card numbers.pdf'; // addimage.pdf, newsletter.pdf

      try {
        const doc = await PDFNet.PDFDoc.createFromFilePath(inputURL + inputFilename);
        doc.initSecurityHandler();

        const txtSearch = await PDFNet.TextSearch.create();
        let mode = PDFNet.TextSearch.Mode.e_whole_word + PDFNet.TextSearch.Mode.e_page_stop; // Uses both whole word and page stop
        let pattern = 'joHn sMiTh';

        txtSearch.begin(doc, pattern, mode); // searches for the "pattern" in the document while following the inputted modes.

        let step = 0;

        // call Run() iteratively to find all matching instances of the word 'joHn sMiTh'
        /* eslint-disable-next-line no-constant-condition */
        while (true) {
          const result = await txtSearch.run();
          let hlts;
          if (result.code === PDFNet.TextSearch.ResultCode.e_found) {
            if (step === 0) { // Step 0: found "John Smith"
              // note that, here, 'ambient_str' and 'highlights' are not written to,
              // as 'e_ambient_string' and 'e_highlight' are not set.
              console.log(result.out_str + "'s credit card number is: ");

              // now switch to using regular expressions to find John's credit card number
              mode = await txtSearch.getMode();
              mode += PDFNet.TextSearch.Mode.e_reg_expression + PDFNet.TextSearch.Mode.e_highlight;
              txtSearch.setMode(mode);
              pattern = '\\d{4}-\\d{4}-\\d{4}-\\d{4}'; // or "(\\d{4}-){3}\\d{4}"
              txtSearch.setPattern(pattern);

              ++step;
            } else if (step === 1) {
              // step 1: found John's credit card number
              console.log('  ' + result.out_str);
              // note that, here, 'hlts' is written to, as 'e_highlight' has been set.
              // output the highlight info of the credit card number.
              hlts = result.highlights;
              hlts.begin(doc);
              while ((await hlts.hasNext())) {
                const highlightPageNum = await hlts.getCurrentPageNumber();
                console.log('The current highlight is from page: ' + highlightPageNum);
                await hlts.next();
              }
              // see if there is an AMEX card number
              pattern = '\\d{4}-\\d{6}-\\d{5}';
              txtSearch.setPattern(pattern);

              ++step;
            } else if (step === 2) {
              // found an AMEX card number
              console.log('\nThere is an AMEX card number:\n  ' + result.out_str);

              // change mode to find the owner of the credit card; supposedly, the owner's
              // name proceeds the number
              mode = await txtSearch.getMode();
              mode += PDFNet.TextSearch.Mode.e_search_up;
              txtSearch.setMode(mode);
              pattern = '[A-z]++ [A-z]++';
              txtSearch.setPattern(pattern);

              ++step;
            } else if (step === 3) {
              // found the owner's name of the AMEX card
              console.log("Is the owner's name:\n  " + result.out_str + '?');

              // add a link annotation based on the location of the found instance
              hlts = result.highlights;
              await hlts.begin(doc); 
              while ((await hlts.hasNext())) {
                const curPage = await doc.getPage((await hlts.getCurrentPageNumber()));
                const quadArr = await hlts.getCurrentQuads();
                for (let i = 0; i < quadArr.length; ++i) {
                  const currQuad = quadArr[i];
                  const x1 = Math.min(Math.min(Math.min(currQuad.p1x, currQuad.p2x), currQuad.p3x), currQuad.p4x);
                  const x2 = Math.max(Math.max(Math.max(currQuad.p1x, currQuad.p2x), currQuad.p3x), currQuad.p4x);
                  const y1 = Math.min(Math.min(Math.min(currQuad.p1y, currQuad.p2y), currQuad.p3y), currQuad.p4y);
                  const y2 = Math.max(Math.max(Math.max(currQuad.p1y, currQuad.p2y), currQuad.p3y), currQuad.p4y);

                  const hyperLink = await PDFNet.LinkAnnot.create(doc, (await PDFNet.Rect.init(x1, y1, x2, y2)));
                  await hyperLink.setAction((await PDFNet.Action.createURI(doc, 'http://www.pdftron.com')));
                  await curPage.annotPushBack(hyperLink);
                }
                hlts.next();
              }
              await doc.save('../TestFiles/Output/credit card numbers_linked.pdf', PDFNet.SDFDoc.SaveOptions.e_linearized);
              break;
            }
          } else if (result.code === PDFNet.TextSearch.ResultCode.e_page) {
            // you can update your UI here, if needed
            console.log('page end');
          } else if (result.code === PDFNet.TextSearch.ResultCode.e_done) {
            break;
          }
        }
      } catch (err) {
        console.log(err);
      }
    };
    PDFNet.runWithCleanup(main, PDFTronLicense.Key).catch(function(error){console.log('Error: ' + JSON.stringify(error));}).then(function(){return PDFNet.shutdown();});
  };
  exports.runTextSearchTest();
})(exports);
// eslint-disable-next-line spaced-comment
//# sourceURL=TextSearchTest.js
```

{% endcode %}
{% endtab %}

{% tab title="PHP" %}
{% code lineNumbers="true" %}

```php
<?php
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2023 by Apryse Software Inc. All Rights Reserved.
// Consult LICENSE.txt regarding license information.
//---------------------------------------------------------------------------------------
if(file_exists("../../../PDFNetC/Lib/PDFNetPHP.php"))
include("../../../PDFNetC/Lib/PDFNetPHP.php");
include("../../LicenseKey/PHP/LicenseKey.php");

// Relative path to the folder containing the test files.
$input_path = getcwd()."/../../TestFiles/";
$output_path = $input_path."Output/";

	PDFNet::Initialize($LicenseKey);
	PDFNet::GetSystemFontList();    // Wait for fonts to be loaded if they haven't already. This is done because PHP can run into errors when shutting down if font loading is still in progress.

	$doc = new PDFDoc($input_path."credit card numbers.pdf");
	$doc->InitSecurityHandler();

	$txt_search = new TextSearch();
	$mode = TextSearch::e_whole_word | TextSearch::e_page_stop;
	$pattern = "joHn sMiTh";

	//call Begin() method to initialize the text search.
	$txt_search->Begin( $doc, $pattern, $mode );

	$step = 0;
	
	//call Run() method iteratively to find all matching instances.
	while ( true )
	{
		$searchResult = $txt_search->Run();
		if ( $searchResult->IsFound() )
		{
			if ( $step == 0 )
			{	//step 0: found "John Smith"
				//note that, here, 'ambient_string' and 'hlts' are not written to, 
				//as 'e_ambient_string' and 'e_highlight' are not set.

				echo nl2br($searchResult->GetMatch()."'s credit card number is: \n");

				//now switch to using regular expressions to find John's credit card number
				$mode = $txt_search->GetMode();
				$mode |= TextSearch::e_reg_expression | TextSearch::e_highlight;
				$txt_search->SetMode($mode);
				$pattern = "\\d{4}-\\d{4}-\\d{4}-\\d{4}"; //or "(\\d{4}-){3}\\d{4}"
				$txt_search->SetPattern($pattern);

				++$step;
			}
			else if ( $step == 1 )
			{
				//step 1: found John's credit card number
				echo nl2br("  ".$searchResult->GetMatch()."\n");
				
				//note that, here, 'hlts' is written to, as 'e_highlight' has been set.
				//output the highlight info of the credit card number.
				$hlts = $searchResult->GetHighlights();
				$hlts->Begin($doc);
				while ( $hlts->HasNext() )
				{
					echo nl2br("The current highlight is from page: ".$hlts->GetCurrentPageNumber()."\n");
					$hlts->Next();
				}

				//see if there is an AMEX card number
				$pattern = "\\d{4}-\\d{6}-\\d{5}";
				$txt_search->SetPattern($pattern);

				++$step;
			}
			else if ( $step == 2 )
			{
				//found an AMEX card number
				echo nl2br("\nThere is an AMEX card number:\n  ".$searchResult->GetMatch()."\n");

				//change mode to find the owner of the credit card; supposedly, the owner's
				//name proceeds the number
				$mode = $txt_search->GetMode();
				$mode |= TextSearch::e_search_up;
				$txt_search->SetMode($mode);
				$pattern = "[A-z]++ [A-z]++";
				$txt_search->SetPattern($pattern);

				++$step;
			}
			else if ( $step == 3 )
			{
				//found the owner's name of the AMEX card
				echo nl2br("Is the owner's name:\n  ".$searchResult->GetMatch()."?\n");

				//add a link annotation based on the location of the found instance
				$hlts = $searchResult->GetHighlights();
				$hlts->Begin($doc);
				while ( $hlts->HasNext() )
				{
					$cur_page= $doc->GetPage($hlts->GetCurrentPageNumber());
					$quadsInfo = $hlts->GetCurrentQuads();

					for ( $i = 0; $i < $quadsInfo->size(); ++$i )
					{
						//assume each quad is an axis-aligned rectangle
						$q = $quadsInfo->get($i);
						$x1 = min(min(min($q->p1->x, $q->p2->x), $q->p3->x), $q->p4->x);
						$x2 = max(max(max($q->p1->x, $q->p2->x), $q->p3->x), $q->p4->x);
						$y1 = min(min(min($q->p1->y, $q->p2->y), $q->p3->y), $q->p4->y);
						$y2 = max(max(max($q->p1->y, $q->p2->y), $q->p3->y), $q->p4->y);
						$hyper_link = Link::CreateAnnot($doc->GetSDFDoc(), new Rect($x1, $y1, $x2, $y2), 
										Action::CreateURI($doc->GetSDFDoc(), "http://www.pdftron.com"));
						$cur_page->AnnotPushBack($hyper_link);
					}
					$hlts->Next();
				}
				
				$doc->Save($output_path."credit card numbers_linked.pdf", SDFDoc::e_linearized);

				break;
			}
		}
		else if ( $code == TextSearch::e_page )
		{
			//you can update your UI here, if needed
		}
		else
		{
			break;
		}
	}
	
	$doc->Close();	
	PDFNet::Terminate();
?>
```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code lineNumbers="true" %}

```python
#---------------------------------------------------------------------------------------
# Copyright (c) 2001-2023 by Apryse Software Inc. All Rights Reserved.
# Consult LICENSE.txt regarding license information.
#---------------------------------------------------------------------------------------

import site
site.addsitedir("../../../PDFNetC/Lib")
import sys
from PDFNetPython import *

sys.path.append("../../LicenseKey/PYTHON")
from LicenseKey import *

# This sample illustrates the basic text search capabilities of PDFNet.

# Relative path to the folder containing the test files.
input_path = "../../TestFiles/"
output_path = "../../TestFiles/Output/"

def main():
    # Initialize PDFNet
    PDFNet.Initialize(LicenseKey)
    doc = PDFDoc(input_path + "credit card numbers.pdf")
    doc.InitSecurityHandler()
    
    txt_search = TextSearch()
    mode = TextSearch.e_whole_word | TextSearch.e_page_stop
    
    pattern = "joHn sMiTh"
    
    # call Begin() method to initialize the text search.
    txt_search.Begin(doc, pattern, mode)

    step = 0
    
    # call Run() method iteratively to find all matching instances.
    while True:
        searchResult = txt_search.Run()
        if searchResult.IsFound():
            if step == 0:
                # step 0: found "John Smith"
                # note that, here, 'ambient_string' and 'hlts' are not written to, 
                # as 'e_ambient_string' and 'e_highlight' are not set.
                
                print(str(searchResult.GetMatch()) + "'s credit card number is: ")
                
                # now switch to using regular expressions to find John's credit card number
                mode = txt_search.GetMode()
                mode |= TextSearch.e_reg_expression | TextSearch.e_highlight
                txt_search.SetMode(mode)
                pattern = "\\d{4}-\\d{4}-\\d{4}-\\d{4}"     #or "(\\d{4}-){3}\\d{4}"
                txt_search.SetPattern(pattern)
                step = step + 1
            elif step == 1:
                # step 1: found John's credit card number
                print("  " + searchResult.GetMatch())
                
                # note that, here, 'hlts' is written to, as 'e_highligh' has been set.
                # output the highlight info of the credit card number
                hlts = searchResult.GetHighlights()
                hlts.Begin(doc)
                while hlts.HasNext():
                    print("The current highlight is from page: " + str(hlts.GetCurrentPageNumber()))
                    hlts.Next()
                    
                # see if there is an AMEX card number
                pattern = "\\d{4}-\\d{6}-\\d{5}"
                txt_search.SetPattern(pattern)
                
                step = step + 1
            elif step == 2:
                # found an AMEX card number
                print("\nThere is an AMEX card number:\n  " + searchResult.GetMatch())
                
                # change mode to find the owner of the credit card; supposedly, the owner's
                # name proceeds the number
                mode = txt_search.GetMode()
                mode |= TextSearch.e_search_up
                txt_search.SetMode(mode)
                pattern = "[A-z]++ [A-z]++"
                txt_search.SetPattern(pattern)
                step = step + 1
            elif step == 3:
                # found the owner's name of the AMEX card
                print("Is the owner's name:\n  " + searchResult.GetMatch() + "?")
                
                # add a link annotation based on the location of the found instance
                hlts = searchResult.GetHighlights()
                hlts.Begin(doc)
                
                while (hlts.HasNext()):
                    cur_page = doc.GetPage(hlts.GetCurrentPageNumber())
                    quadsInfo = hlts.GetCurrentQuads()
                    
                    i = 0
                    while i < len(quadsInfo):
                        q = quadsInfo[i]
                        # assume each quad is an axis-aligned rectangle                        
                        x1 = min(min(min(q.p1.x, q.p2.x), q.p3.x), q.p4.x)
                        x2 = max(max(max(q.p1.x, q.p2.x), q.p3.x), q.p4.x)
                        y1 = min(min(min(q.p1.y, q.p2.y), q.p3.y), q.p4.y)
                        y2 = max(max(max(q.p1.y, q.p2.y), q.p3.y), q.p4.y)
                        hyper_link = Link.Create(doc.GetSDFDoc(), Rect(x1, y1, x2, y2), Action.CreateURI(doc.GetSDFDoc(), "http://www.pdftron.com"))
                        cur_page.AnnotPushBack(hyper_link)
                        i = i + 1                    
                    hlts.Next()
                doc.Save(output_path + "credit card numbers_linked.pdf", SDFDoc.e_linearized)
                break
        elif code == TextSearch.e_page:
            pass
        else:
            break
        
    doc.Close()
    PDFNet.Terminate()
        
if __name__ == '__main__':
    main()
```

{% endcode %}
{% endtab %}

{% tab title="Ruby" %}
{% code lineNumbers="true" %}

```ruby
#---------------------------------------------------------------------------------------
# Copyright (c) 2001-2023 by Apryse Software Inc. All Rights Reserved.
# Consult LICENSE.txt regarding license information.
#---------------------------------------------------------------------------------------

require '../../../PDFNetC/Lib/PDFNetRuby'
include PDFNetRuby
require '../../LicenseKey/RUBY/LicenseKey'

$stdout.sync = true

# This sample illustrates the basic text search capabilities of PDFNet.

# Relative path to the folder containing the test files.
input_path = "../../TestFiles/"
output_path = "../../TestFiles/Output/"

	# Initialize PDFNet
	PDFNet.Initialize(PDFTronLicense.Key)
	doc = PDFDoc.new(input_path + "credit card numbers.pdf")
	doc.InitSecurityHandler
	
	txt_search = TextSearch.new
	mode = TextSearch::E_whole_word | TextSearch::E_page_stop
	
	pattern = "joHn sMiTh"
	
	# call Begin method to initialize the text search.
	txt_search.Begin(doc, pattern, mode)

	step = 0

	# call Run method iteratively to find all matching instances.
	while true do
		searchResult = txt_search.Run
		if searchResult.IsFound
			case step
			when 0
				# step 0: found "John Smith"
				# note that, here, 'ambient_string' and 'hlts' are not written to, 
				# as 'e_ambient_string' and 'e_highlight' are not set.
				
				puts searchResult.GetMatch + "'s credit card number is: "
				
				# now switch to using regular expressions to find John's credit card number
				mode = txt_search.GetMode
				mode |= TextSearch::E_reg_expression | TextSearch::E_highlight
				txt_search.SetMode(mode)
				pattern = "\\d{4}-\\d{4}-\\d{4}-\\d{4}"	 #or "(\\d{4}-){3}\\d{4}"
				txt_search.SetPattern(pattern)
				step = step + 1
			when 1
				# step 1: found John's credit card number
				puts "  " + searchResult.GetMatch
				
				# note that, here, 'hlts' is written to, as 'e_highligh' has been set.
				# output the highlight info of the credit card number
				hlts = searchResult.GetHighlights
				hlts.Begin(doc)
				while hlts.HasNext
					puts "The current highlight is from page: " + hlts.GetCurrentPageNumber.to_s
					hlts.Next
				end
					
				# see if there is an AMEX card number
				pattern = "\\d{4}-\\d{6}-\\d{5}"
				txt_search.SetPattern(pattern)
				
				step = step + 1
			when 2
				# found an AMEX card number
				puts "\nThere is an AMEX card number:\n  " + searchResult.GetMatch
				
				# change mode to find the owner of the credit card; supposedly, the owner's
				# name proceeds the number
				mode = txt_search.GetMode
				mode |= TextSearch::E_search_up
				txt_search.SetMode(mode)
				pattern = "[A-z]++ [A-z]++"
				txt_search.SetPattern(pattern)
				step = step + 1
			when 3
				# found the owner's name of the AMEX card
				puts "Is the owner's name:\n  " + searchResult.GetMatch + "?"
				
				# add a link annotation based on the location of the found instance
				hlts = searchResult.GetHighlights
				hlts.Begin(doc)
				
				while hlts.HasNext do
					cur_page = doc.GetPage(hlts.GetCurrentPageNumber)
					quadsInfo = hlts.GetCurrentQuads

					i = 0
					while i < quadsInfo.size do
						q = quadsInfo[i]
						# assume each quad is an axis-aligned rectangle						
						x1 = [q.p1.x, q.p2.x, q.p3.x, q.p4.x].min
						x2 = [q.p1.x, q.p2.x, q.p3.x, q.p4.x].max
						y1 = [q.p1.y, q.p2.y, q.p3.y, q.p4.y].min
						y2 = [q.p1.y, q.p2.y, q.p3.y, q.p4.y].max
						hyper_link = Link.Create(doc.GetSDFDoc, Rect.new(x1, y1, x2, y2), Action.CreateURI(doc.GetSDFDoc, "http://www.pdftron.com"))
						cur_page.AnnotPushBack(hyper_link)
						i = i + 1
					end			
					hlts.Next
				end
				doc.Save(output_path + "credit card numbers_linked.pdf", SDFDoc::E_linearized)
				break
			end
		elsif code == TextSearch::E_page
		else
			break
		end
	end	
	doc.Close
	PDFNet.Terminate
```

{% endcode %}
{% endtab %}

{% tab title="VB" %}
{% code lineNumbers="true" %}

```vb
'
' Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
'

Imports System
Imports pdftron
Imports pdftron.Common
Imports pdftron.Filters
Imports pdftron.SDF
Imports pdftron.PDF

Module TextSearchTestVB
    Dim pdfNetLoader As PDFNetLoader
    Sub New()
        pdfNetLoader = pdftron.PDFNetLoader.Instance()
    End Sub

    Sub Main()
        PDFNet.Initialize(PDFTronLicense.Key)
        Dim input_path As String = "../../../../TestFiles/"

        Try

            Using doc As PDFDoc = New PDFDoc(input_path & "credit card numbers.pdf")
                doc.InitSecurityHandler()
                Dim page_num As Int32 = 0
                Dim result_str As String = "", ambient_string As String = ""
                Dim hlts As Highlights = New Highlights()
                Dim txt_search As TextSearch = New TextSearch()
                Dim mode As Int32 = CInt((TextSearch.SearchMode.e_whole_word Or TextSearch.SearchMode.e_page_stop Or TextSearch.SearchMode.e_highlight))
                Dim pattern As String = "joHn sMiTh"
                txt_search.Begin(doc, pattern, mode, -1, -1)
                Dim step_ As Integer = 0

                While True
                    Dim code As TextSearch.ResultCode = txt_search.Run(page_num, result_str, ambient_string, hlts)

                    If code = TextSearch.ResultCode.e_found Then

                        If step_ = 0 Then
                            Console.WriteLine(result_str & "'s credit card number is: ")
                            mode = txt_search.GetMode()
                            mode = mode Or CInt((TextSearch.SearchMode.e_reg_expression Or TextSearch.SearchMode.e_highlight))
                            txt_search.SetMode(mode)
                            pattern = "\d{4}-\d{4}-\d{4}-\d{4}"
                            txt_search.SetPattern(pattern)
                            step_ += 1
                        ElseIf step_ = 1 Then
                            Console.WriteLine("  " & result_str)
                            hlts.Begin(doc)

                            While hlts.HasNext()
                                Console.WriteLine("The current highlight is from page: " & hlts.GetCurrentPageNumber())
                                hlts.Next()
                            End While

                            pattern = "\d{4}-\d{6}-\d{5}"
                            txt_search.SetPattern(pattern)
                            step_ += 1
                        ElseIf step_ = 2 Then
                            Console.WriteLine(vbLf & "There is an AMEX card number:" & vbLf & "  " & result_str)
                            mode = txt_search.GetMode()
                            mode = mode Or CInt((TextSearch.SearchMode.e_search_up))
                            txt_search.SetMode(mode)
                            pattern = "[A-z]++ [A-z]++"
                            txt_search.SetPattern(pattern)
                            step_ += 1
                        ElseIf step_ = 3 Then
                            Console.WriteLine("Is the owner's name:" & vbLf & "  " & result_str & "?")
                            hlts.Begin(doc)
                            While hlts.HasNext()
                                Dim cur_page As Page = doc.GetPage(hlts.GetCurrentPageNumber())
                                Dim quads As Double() = hlts.GetCurrentQuads()
                                Dim quad_count As Integer = quads.Length / 8

                                For i As Integer = 0 To quad_count - 1
                                    Dim offset As Integer = 8 * i
                                    Dim x1 As Double = Math.Min(Math.Min(Math.Min(quads(offset + 0), quads(offset + 2)), quads(offset + 4)), quads(offset + 6))
                                    Dim x2 As Double = Math.Max(Math.Max(Math.Max(quads(offset + 0), quads(offset + 2)), quads(offset + 4)), quads(offset + 6))
                                    Dim y1 As Double = Math.Min(Math.Min(Math.Min(quads(offset + 1), quads(offset + 3)), quads(offset + 5)), quads(offset + 7))
                                    Dim y2 As Double = Math.Max(Math.Max(Math.Max(quads(offset + 1), quads(offset + 3)), quads(offset + 5)), quads(offset + 7))
                                    Dim hyper_link As pdftron.PDF.Annots.Link = pdftron.PDF.Annots.Link.Create(doc, New Rect(x1, y1, x2, y2), pdftron.PDF.Action.CreateURI(doc, "http://www.pdftron.com"))
                                    hyper_link.RefreshAppearance()
                                    cur_page.AnnotPushBack(hyper_link)
                                Next

                                hlts.Next()
                            End While

                            Dim output_path As String = "../../../../TestFiles/Output/"
                            doc.Save(output_path & "credit card numbers_linked.pdf", SDFDoc.SaveOptions.e_linearized)
                            Exit While
                        End If
                    ElseIf code = TextSearch.ResultCode.e_page Then
                    Else
                        Exit While
                    End If
                End While
            End Using
        Catch e As PDFNetException
            Console.WriteLine(e.Message)
        End Try
        PDFNet.Terminate()
    End Sub
End Module
```

{% endcode %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/core/get-started/samples/textsearchtest.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
