> 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/ios/search/text.md).

# Text search

Learn how to add text search functionality to an iOS viewer using the PTTextSearchViewController class. Highlight search results, navigate through documents, and refine search options with ease. Explo

There are two parts to text searching. First is the UI component that is presented to the user. Second is an API guide to perform the text search functionality.

{% tabs %}
{% tab title="UI component" %}

## Add text search to iOS viewer

The [`PTTextSearchViewController`](https://sdk.apryse.com/api/ios/Classes/PTTextSearchViewController.html) class allows the user to enter and search text in a document. Search results are automatically highlighted in the document and a toolbar with navigation buttons allows searching forward or backward through the document. The core text search functionality is provided by the `PTPDFViewCtrl`'s text search methods.

![](https://4149080208-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgY6xtY9ZQd9XMpvWlGM0%2Fuploads%2Fgit-blob-5b996e58859c24b85e6b62bc67642b88c7b6715f%2F751784ed5090a448a7c6c10669313b4ca6f4f856-1242x2208.png?alt=media)

The search view controller is part of the Tools library, so make sure you have [added the Tools library to your project](/ios/ui-customization/setup.md).

## Showing a text search view controller

To create and set up a text search view controller, supply a `PTPDFViewCtrl` instance to the `PTTextSearchViewController` designated initializer:

{% tabs %}
{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
let textSearchViewController = PTTextSearchViewController(pdfViewCtrl: pdfViewCtrl)
textSearchViewController.delegate = self

let navigationController = UINavigationController(rootViewController: textSearchViewController)
navigationController.modalPresentationStyle = .custom

self.present(navigationController, animated: true, completion: nil)
```

{% endcode %}
{% endtab %}

{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
// Initialize search view controller with a PTPDFViewCtrl instance.
PTTextSearchViewController *textSearchViewController = [[PTTextSearchViewController alloc] initWithPDFViewCtrl:pdfViewCtrl];
textSearchViewController.delegate = self;

UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:textSearchViewController];
navigationController.modalPresentationStyle = UIModalPresentationCustom;

[self presentViewController:navigationController animated:YES completion:nil];
```

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

{% hint style="info" %}
**The search view controller does not create its own top navigation bar, so it must be pushed onto a navigation controller's stack.**
{% endhint %}

## Search results list view

The [`PTTextSearchViewController`](https://sdk.apryse.com/api/ios/Classes/PTTextSearchViewController.html) also presents the search results in a [`UITableView`](https://developer.apple.com/uikit/uitableview/) for fast and easy navigation. Selecting any result in the table view will immediately navigate to that result and highlight it.

![](https://4149080208-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgY6xtY9ZQd9XMpvWlGM0%2Fuploads%2Fgit-blob-0f6e4cec66513b1e061b53385da57beb32df4d8b%2F08cf4fd3cf391932800026c39ccb26afb382d8d2-1242x2208.png?alt=media)

## Search options

The [`PTTextSearchViewController`](https://sdk.apryse.com/api/ios/Classes/PTTextSearchViewController.html) interface also allows the user to refine the search to be case-sensitive, or to match whole words only:

![](https://4149080208-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FgY6xtY9ZQd9XMpvWlGM0%2Fuploads%2Fgit-blob-78bd27828d88921be427867d6e894bdf06e92ec3%2Fa495a97d93efa8972f0dce4876598b822261e148-1242x2208.png?alt=media)

## The text search view controller delegate

The [`PTTextSearchViewControllerDelegate`](https://sdk.apryse.com/api/ios/Protocols/PTTextSearchViewControllerDelegate.html) protocol allows the adopting class (usually the containing view controller, as in this guide) to be notified when the view controller has been dismissed. This can be used to show or hide other content as appropriate.
{% endtab %}

{% tab title="API guide" %}

## Text search API for iOS

To search for text in a PDF using regular expression and then apply a link annotation on the highlighted result.

{% hint style="info" %}
In this example, we add a link annotation but any other types of annotations can be applied here such as redaction annotations in the case of a search and redact workflow.
{% endhint %}

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

```objc
PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: filename];
PTTextSearch *txt_search = [[PTTextSearch alloc] init];
unsigned int mode = e_ptwhole_word | e_ptpage_stop;
NSString *pattern = @"";

//use regular expression to find credit card number
mode |= e_ptreg_expression | e_pthighlight;
[txt_search SetMode: mode];
pattern = @"\\d{4}-\\d{4}-\\d{4}-\\d{4}"; //or "(\\d{4}-){3}\\d{4}"
[txt_search SetPattern: pattern];

//call Begin() method to initialize the text search.
[txt_search Begin: doc pattern: pattern mode: mode start_page: -1 end_page: -1];
PTSearchResult *result = [txt_search Run];

if ( result ) 
{
  //add a link annotation based on the location of the found instance
  PTHighlights *hlts = [result GetHighlights];
  [hlts Begin: doc];
  while ( [hlts HasNext] )
  {
    PTPage *cur_page = [doc GetPage: [hlts GetCurrentPageNumber]];
    PTVectorQuadPoint *quads = [hlts GetCurrentQuads];
    int i = 0;
    for ( ; i < [quads size]; ++i )
    {
      //assume each quad is an axis-aligned rectangle
      PTQuadPoint *q = [quads get: i];
      double x1 = MIN(MIN(MIN([[q getP1] getX], [[q getP2] getX]), [[q getP3] getX]), [[q getP4] getX]);
      double x2 = MAX(MAX(MAX([[q getP1] getX], [[q getP2] getX]), [[q getP3] getX]), [[q getP4] getX]);
      double y1 = MIN(MIN(MIN([[q getP1] getY], [[q getP2] getY]), [[q getP3] getY]), [[q getP4] getY]);
      double y2 = MAX(MAX(MAX([[q getP1] getY], [[q getP2] getY]), [[q getP3] getY]), [[q getP4] getY]);
      PTPDFRect * rect = [[PTPDFRect alloc] initWithX1: x1 y1: y1 x2: x2 y2: y2];
      PTAction *action = [PTAction CreateURI: [doc GetSDFDoc] uri: @"http://www.apryse.com"];

      PTLink *hyper_link = [PTLink CreateWithAction: [doc GetSDFDoc] pos: rect action: action];
      [cur_page AnnotPushBack: hyper_link];
    }
    [hlts Next];
  }
}
```

{% endcode %}
{% endtab %}

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

```swift
let doc: PTPDFDoc! = PTPDFDoc(filepath: filename)
let txt_search: PTTextSearch! = PTTextSearch()
var mode = e_ptwhole_word.rawValue | e_ptpage_stop.rawValue
var pattern = ""

//use regular expression to find credit card number
mode |= e_ptreg_expression.rawValue | e_pthighlight.rawValue
txt_search.setMode(mode)
pattern = "\\d{4}-\\d{4}-\\d{4}-\\d{4}" //or "(\\d{4}-){3}\\d{4}"
txt_search.setPattern(pattern)

//call Begin() method to initialize the text search.
txt_search.begin(doc, pattern: pattern, mode: mode, start_page: -1, end_page: -1)
let result: PTSearchResult! = txt_search.run()

if (result != nil) {
  //add a link annotation based on the location of the found instance
  let hlts: PTHighlights = result.getHighlights()
  hlts.begin(doc)
  while hlts.hasNext() {
    let cur_page: PTPage = doc.getPage(UInt32(hlts.getCurrentPageNumber()))
    let quads: PTVectorQuadPoint = hlts.getCurrentQuads()
    var i: Int = 0
    
    while i < quads.size() {
      //assume each quad is an axis-aligned rectangle
      let q: PTQuadPoint = quads.get(Int32(i))
      let x1: Double = min(min(min(q.getP1().getX(), q.getP2().getX()), q.getP3().getX()), q.getP4().getX())
      let x2: Double = max(max(max(q.getP1().getX(), q.getP2().getX()), q.getP3().getX()), q.getP4().getX())
      let y1: Double = min(min(min(q.getP1().getY(), q.getP2().getY()), q.getP3().getY()), q.getP4().getY())
      let y2: Double = max(max(max(q.getP1().getY(), q.getP2().getY()), q.getP3().getY()), q.getP4().getY())
      let rect = PTPDFRect(x1: x1, y1: y1, x2: x2, y2: y2)
      let action = PTAction.createURI(doc.getSDFDoc(), uri: "http://www.apryse.com")
      let hyper_link = PTLink.create(withAction: doc.getSDFDoc(), pos: rect, action: action)
      cur_page.annotPushBack(hyper_link)
      i += 1
    }
    hlts.next()
}
```

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

[Search PDF files for text](/ios/get-started/samples.md#textsearch) Full code sample which shows how to use TextSearch to search text on PDF pages using regular expressions.
{% 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/ios/search/text.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.
