Replace only the Nth match

10 May 2025

Here is another practical task. We need to replace only the second or following match in each file.

For example, we want to insert <a name="..."> tags before the second and any subsequent headers in each HTML file. There are multiple headers in each file:

Matching <h2> headers

And we want to insert a name to be able to refer to each header. The final result should look like this (the added tag is bold):

<a name="international_search_test"><h2>International search test</h2>

We can solve this task with a lookbehind:

Matching the second, the third, etc. tags
(?<=<h2>.*?)<h2>

This regular expression matches <h2>, but only if there is another <h2> before it.

With Aba Search and Replace, there is a more flexible way to do this. You can match all <h2> tags, but change only the second, the third, etc. tags leaving the first tag intact. The pattern is simple:

<h2>(.*?)</h2>

But in the replacement, we check if the match number is equal to one:

\( if Aba.matchNoInFile() == 1 {
   \0
} else {
   '<a name="' \1.replace(' ', '_').toLower() '">' \0
} )

If yes, we return the whole match \0 without any change. If not, we add <a name="..."> before it. We also use the toLower function to convert the name to lowercase and the replace function to replace spaces with underscores.

Replacing the second, the third, etc. tags

You can easily modify this one-liner to replace the first three tags in each file only, or replace every second tag, which is more complicated with a lookbehind.

Aba Search and Replace screenshot

Replacing text in several files used to be a tedious and error-prone task. Aba Search and Replace solves the problem, allowing you to correct errors on your web pages, replace banners and copyright notices, change method names, and perform other text-processing tasks.

This is a blog about Aba Search and Replace, a tool for replacing text in multiple files.