Understanding Regular Expressions

What a pattern is

You already search PDFs by typing words. A pattern lets you search for a shape instead of exact words.

Suppose a 400-page standard says “see page 12”, “see page 147” and “see page 9”. There is no single piece of text you can type that finds all three — the number is different every time. But they all share a shape: the words see page, then a space, then some digits. Written as a pattern, that shape is:

see page \d+

\d means “any digit”. + means “one or more of those”. Everything else is ordinary text that matches itself. That is the whole idea; the rest of this page is just more shapes.

Tip

When not to use a pattern. If you are looking for the literal words Confidential Draft and nothing else, just type them and leave Use regular expressions switched off. Patterns are for when the thing you want varies — a page number that changes, a date in any month, a section number of unknown depth.

Before writing a pattern, it helps to answer three questions:

Building your first pattern

Here is how one of the patterns supplied with TOC Builder was built up, one step at a time. The goal: find every cross-reference of the form “see page 47” in a long specification.

  1. see page 47
    Works once. Useless — it only finds page 47.
  2. see page \d+
    Now any page number matches. But it fails on “see  page 47” with two spaces, and on “See page 47” with a capital S.
  3. see\s+page\s+\d+
    \s is any space, tab or line break and + means one or more, so any amount of spacing works. This matters specifically in PDFs: text pulled out of a PDF often has irregular spacing where the original was justified, so a single typed space frequently misses matches that look fine on screen.
  4. see\s+page\s+(\d+)
    The brackets mark the part you want to keep. The page number is now capture group 1.

That last line is exactly the supplied library entry Page references › see page N. The library is not magic — you have just derived one of its 128 entries.

Literal text, and the characters that are not literal

Almost everything you type matches itself. These twelve characters do not — they have a special meaning:

. ^ $ * + ? ( ) [ ] { } | \

To match one of them for real, put a backslash in front of it.

The commonest mistake

. matches any single character, not a full stop.

Fig.12 finds “Fig.12” — and also “Fig512”, “Fig 12” and “FigX12”.
Fig\.12 finds only “Fig.12”.

This bites hardest with section numbers: 3.4.5 matches “3.4.5” but also “31465”.

Matching a kind of character

WriteMeansIn a document
\dany digitthe 7 in “Figure 7”
\wletter, digit or underscoreany character of “Appendix”
\sspace, tab or line breakthe gap in “see page”
\D \W \Sthe opposite of each
[A-Z]one capital letterthe A in “Appendix A”
[0-9]same as \d
[IVXLCDM]one Roman numeral letterthe X in “Part XIV”
[^0-9]anything that is not a digit^ inside brackets means “not”
[-–]a hyphen or an en dash“12-18” and “12–18”

Tip

That last row earns its place. Documents produced from Word or InDesign use en dashes in page ranges, so a pattern written with a plain hyphen silently misses half the document. The supplied entry Page references › pages N–M uses [-–] for exactly this reason.

How many

WriteMeansExampleFinds
*zero or moreFig\.\s*12Fig.12 and Fig. 12
+one or more\d+3, 47, 1024
?optional — none or oneFigs?Fig and Figs
{4}exactly four\d{4}2026
{2,4}between two and four[A-Z]{2,4}-\d+ABC-1234
{2,}two or more\d{2,}47, 1024

A repeat always applies to the one thing immediately before it. In Figs? the ? applies to the s alone, not to the whole word — which is why it finds both “Fig” and “Figs”.

Why your pattern matched far too much

Suppose a line reads:

Approved by "J. Smith" and "R. Patel" on 4 March

You want the quoted names, so you write "(.+)". What you get back is J. Smith" and "R. Patel — one huge match. .+ is greedy: it takes as much as it possibly can and only gives back what it must.

Adding a question mark after the repeat makes it take as little as possible instead. "(.+?)" gives you J. Smith, then R. Patel.

Rule of thumb

The moment you write .+ or .* between two markers, write .+? or .*? instead.

Where on the page

WriteMeansExample
^start of the text^INTENTIONALLY BLANK$
$end of the textPage \d+$
\bthe edge of a word\bTable\s+(\d+) finds “Table 3”, not “Turntable 3”

\b is what makes the supplied entry Page references › p N (\bp\.?\s*(\d+)\b) skip the “p.” inside “Corp.”

Warning

In most features ^ and $ mean the start and end of the whole extracted text of the page, not of each line. Only Generate Links from Rules offers a per-line option (its m checkbox). This is why the supplied Notes and Lists patterns, which begin with ^, behave differently depending on which dialog you paste them into.

Either / or, and grouping

| means “or”: Figure|Table finds whichever appears. Brackets group things so a repeat or an “or” applies to all of them at once.

There are two kinds of bracket. ( ) groups and keeps what is inside. (?: ) groups without keeping. The supplied year pattern uses both:

\b((?:19|20)\d{2})\b

The outer brackets keep the whole year. The inner (?:19|20) only groups the either/or, so that the year has to start 19 or 20 — without it, 19|20\d{2} would mean “the text 19, or 20 followed by two digits”, which is not what anyone wants.

Capture groups — the part you keep

Brackets do two jobs at once: they group things together, and they keep what is inside them.

Invoice #(\d+) matches the whole of “Invoice #4471”, but capture group 1 holds just 4471.

This is not decoration. In several TOC Builder features the captured part is the answer:

FeatureWhat it does with your capture
Split by Pattern Change Uses capture group 1 as the split key. Consecutive pages with the same captured value go into the same file. With no brackets at all, the whole match is used instead.
Generate Links from Rules You put \1 into the action fields to build the link target out of the captured text.
Search and Replace You type $1 in the Replace field to keep part of what you found.
Split output file names {match:PATTERN} puts the first match into the output file name.

A worked example

A statement run has “Invoice 4471” on pages 1–3, “Invoice 4472” on pages 4–9 and “Invoice 4473” on page 10.

Split by Pattern Change with Invoice\s+(\d+) gives three files, split exactly where the number changes.

The same job with Invoice\s+\d+ — no brackets — gives you one file. Every page matches the same whole-match shape, so as far as the feature is concerned nothing ever “changes”. If a split produces a single file when you expected several, a missing pair of brackets is almost always why.

Note

\1 means two different things depending on where you type it.

Inside a pattern, \1 means “the same text that group 1 already matched” — (\w+)\s+\1 finds a doubled word like “the the”.

Inside a Generate Links value field, \1 means “insert what group 1 captured”. See Putting captures back.

Putting captures back

Warning

There are two different replacement notations in TOC Builder, and they are not interchangeable.

FeatureNotation
Search and Replace (bookmark titles)$1$9, $&, $$
Search and Replace URLs in Bookmarks$1
Search and Replace URLs in Links$1
Generate Links from Rules\0\9 only. $1 is inserted as the literal text “$1”.

A worked pair. Bookmarks read “Chapter 4 — Installation” and you want “4. Installation”:

Two more that only apply to Search and Replace: $& inserts the whole match, and $$ inserts a real dollar sign. To turn 1,234.56 into $1,234.56 you would type $$$&.

Capitals and matching

Warning

(?i) does not work in TOC Builder. You may have seen it recommended elsewhere — it is common in other programs — but a pattern beginning (?i) is rejected here as invalid.

Capitals are controlled per feature; see the table below. Where a feature gives you no option, put the choice in the pattern itself: [Ss]ection\s+(\d+) matches both “Section 4” and “section 4”.

Behaviour is not uniform across the product, and this catches people out. The same saved pattern can match differently depending on which dialog uses it:

FeatureCapitals
Search and Replace (bookmarks)Match case checkbox; off by default, so capitals are ignored
Search and Replace URLs (bookmarks and links)Match case checkbox
Find / Edit Bookmark PropertiesMatch case checkbox
Delete Pages by Text SearchMatch case checkbox
Bookmarks from Text PatternsMatch case checkbox, per rule
Highlight Text PatternsMatch case, per pattern
Generate Links from Rulesi checkbox (plus m, g, x, u)
Extract by Text PatternAlways ignores capitals. No option.
Split by Text PatternAlways ignores capitals.
Split by Pattern ChangeAlways ignores capitals.
Delete Text HighlightsAlways matches capitals exactly. No option.

Note

A library entry carries no capitals setting. The library stores the group, name, pattern, description and example — not how it should be matched. If a pattern must always ignore capitals, build that into the pattern with a character class such as [Ff]igure rather than relying on whichever dialog you happen to use it in.

Matching a real full stop, bracket or backslash

Put a backslash in front of any special character to match it literally: \. \( \) \[ \] \$ \? \+ \* \\

The supplied equation pattern shows both meanings of a bracket in one line:

\bEq\.?\s*\((\d+)\)

The \( and \) match the real brackets printed around the number; the plain ( and ) in the middle do the capturing. The \. is a real full stop, and the ? after it makes that full stop optional, so both “Eq. (3)” and “Eq (3)” match.

A Windows path needs each backslash written twice: ([A-Za-z]:\\[A-Za-z0-9_\-\\\. ]+) finds C:\Specs\report.pdf.

Where patterns are used

Patterns are matched against the text extracted from the page, not against what you see on screen. That difference explains most “why did this not match?” puzzles: extracted text can carry odd spacing, and words split across a line break may not join up the way they look.

Features that accept a pattern:

The patterns supplied with TOC Builder

TOC Builder ships with 128 ready-made patterns in 22 groups, available from the Regular Expression Library. Each one now carries a plain-English description of what it finds and an example of text it matches.

The groups are: Basics, Page references, Page labels, Sections, Figures, Tables, Equations, Boxes, Listings, Appendices, Cross-refs, URLs/Files/IDs, Legal/Standards, Dates/Times, Numbers, Codes, Citations, Notes, Lists, Addresses/Phones, Cross-document and General.

Tip

Look in the library before writing anything. One of the 128 is probably close to what you need, and editing a working pattern is far easier than writing one from scratch. Start with the Basics group if the syntax is new to you — those entries exist to be read, not just used.

Testing a pattern safely

  1. Use the Try it box in the Regular Expression Library. Select a pattern and type sample text; it shows every match and the value of each capture group as you type.
  2. Run it on a five-page range first, not the whole document.
  3. Check the number of matches, not just that there are some. Too many matches is the common failure, not zero.
  4. Save the file first. Most of these operations cannot be undone item by item.
  5. When a pattern works, save it into the library with a name and description that say what it finds — so the next person does not have to work it out again.

Ten things that go wrong

SymptomCauseFix
Matched far too much.+ is greedyUse .+?
Matched “Fig512”. means any characterUse \.
Found nothing, pattern looks rightExtracted text has irregular spacingUse \s+ instead of a typed space
Missed half the page rangesDocument uses en dashesUse [-–]
Split produced one fileNo capture groupAdd brackets around the varying part
Replacement inserted the literal “$1”Wrong notation for that dialogUse \1 in Generate Links
“Invalid regular expression”Unbalanced bracket, or an (?i) prefixRead the message — it names the character position
Works in one dialog, not anotherDifferent capitals handlingSee Capitals and matching
Matched inside longer wordsMissing \bWrap the word in \b\b
^ did not workIt means start of the whole page textUse a different anchor, or Generate Links with m

Five jobs from real documents

GoalPatternFeature
Bookmark every numbered section\bSection\s+((?:\d+\.)+\d+)\bBookmarks from Text Patterns
Split a statement run by invoice numberInvoice\s+(\d+)Split by Pattern Change
Renumber “Chapter 4 — Installation” to “4. Installation”find Chapter (\d+) — (.+), replace $1. $2Search and Replace
Extract every page citing a standard\b(ISO\s+\d{4,5}-\d+)\bExtract by Text Pattern
Turn “see page 47” into working linkssee\s+page\s+(\d+) with \1 as the targetGenerate Links from Rules

Learning more

Regular expressions are not a Mapsoft invention. They are a standard notation used by dozens of programs, so anything you learn about them transfers — and there is a great deal of good free material. These are the sites we recommend. They all open in a new tab.

Set the flavour before you test

Regular expressions come in slightly different dialects, usually called flavours. TOC Builder uses the ECMAScript flavour — the same one as JavaScript. On regex101, choose ECMAScript (JavaScript) in the FLAVOR list on the left before you start; it opens in PCRE2 mode, which accepts things TOC Builder will reject.

Even in ECMAScript mode, a few things those sites allow are not available here: look-behind (?<=…), named groups (?<name>…), Unicode property escapes \p{…}, and inline switches such as (?i). Look-ahead — (?=…) and (?!…)is supported. See Not supported.

Note

These are third-party websites. They are not operated by Mapsoft, and we cannot control their content or availability. We list them because we find them useful, not as an endorsement.

See also