Regular expression to match a word but not inside backticks

Viewed 129

Here is an example of different paragraphs

Upgrade is the first word in this paragraph.
In this paragraph, upgrade is the last word.
And this paragraph endsupgrade with upgrade.
But I don't want to upgradefind that word in this command `gigalixir:upgrade`.

As you can see there are 6 instances of upgrade word in above mentioned four lines. I am trying to find all the upgrade words except the one at the last (because that word is inside the command inside backticks). I also do not want to find upgrade words that are not independent.

So in the above sentence following words marked with double * should be selected:

**Upgrade** is the first word in this paragraph.
In this paragraph, **upgrade** is the last word.
And this paragraph endsupgrade with **upgrade**.
But I don't want to upgradefind that word in this command `gigalixir:upgrade`.

I have tried this simple regex:

/\bupgrade\b/gi

That selects all the independent words but I want to ignore the upgrade word inside backticks.

Note: I do not want to use lookahead or lookbehind, because I am executing this regex inside browser and any browser except chrome does not support that.

1 Answers

You can match strings inside backticks and skip them and only match a word upgrade in all other contexts as a whole word:

const text = 'Upgrade is the first word in this paragraph.\nIn this paragraph, upgrade is the last word.\nAnd this paragraph endsupgrade with upgrade.\nBut I don\'t want to upgradefind that word in this command `gigalixir:upgrade`.';
const regex = /(`[^`]*`)|\bupgrade\b/gi;
console.log(text.replace(regex, (x,y) => y || `**${x}**`));

The (`[^`]*`)|\bupgrade\b regex matches

  • (`[^`]*`) - Capturing group 1 (it will help analyze the match structure later): a backtick, zero or more chars other than a backtick, and a backtick
  • | - or
  • \bupgrade\b - a whole word upgrade (case insensitively due to i flag).

The .replace(regex, (x,y) => y || `**${x}**`) means that after a match is found, the match is passed to an arrow function where x is the whole match and y is the Group 1 value. If Group 1 value matches, its value is used to replace the match, else, the whole match is wrapped with double asterisks.

Alternatively, you may use a known workaround with a negative lookahead that will work only in case you have a paired amount of backticks in the string:

\bupgrade\b(?=(?:[^`]*`[^`]*`)*[^`]*$)

See the regex demo.

The (?=(?:[^`]*`[^`]*`)*[^`]*$) lookahead matches a location that is immediately followed with

  • (?:[^`]*`[^`]*`)* zero or more repetitions of any zero or more chars other than a backtick, followed with a backtick, then again any zero or more chars other than a backtick and again a backtick
  • [^`]* - any zero or more chars other than a backtick
  • $ - end of string.
Related