S1r-Lanzelot
S1r-Lanzelot

Reputation: 2266

Regex exact match on number, not digit

I have a scenario where I need to find and replace a number in a large string using javascript. Let's say I have the number 2 and I want to replace it with 3 - it sounds pretty straight forward until I get occurrences like 22, 32, etc.

The string may look like this:
"note[2] 2 2_ someothertext_2 note[32] 2finally_2222 but how about mymomsays2."

I want turn turn it into this:
"note[3] 3 3_ someothertext_3 note[32] 3finally_2222 but how about mymomsays3."

Obviously this means .replace('2','3') is out of the picture so I went to regex. I find it easy to get an exact match when I am dealing with string start to end ie: /^2$/g. But that is not what I have. I tried grouping, digit only, wildcards, etc and I can't get this to match correctly.

Any help on how to exactly match a number (where 0 <= number <= 500 is possible, but no constraints needed in regex for range) would be greatly appreciated.

Upvotes: 2

Views: 1240

Answers (3)

ctwheels
ctwheels

Reputation: 22817

See regex in use here

(\D|\b)2(?!\d)
  • (\D|\b) Capture either a non-digit character or a position that matches a word boundary
  • (?!\d) Negative lookahead ensuring what follows is not a digit

Alternations:

(^|\D)2(?!\d)      # Thanks to @Wiktor in the comments below
(?<!\d)2(?!\d)     # At the time of writing works in Chrome 62+

const regex = /(\D|\b)2(?!\d)/g
const str = `note[2] 2 2_ someothertext_2 note[32] 2finally_2222 but how about mymomsays2.`
const subst = "$13"

console.log(str.replace(regex, subst))

Upvotes: 2

Valdi_Bo
Valdi_Bo

Reputation: 30971

The task is to find (and replace) "single" digit 2, not embedded in a number composed of multiple digits.

In regex terms, this can be expressed as:

  • Match digit 2.
  • Previous char (if any) can not be a digit.
  • Next char (if any) can not be a digit.

The regex for the first condition is straightforward - just 2. In other flavours of regex, e.g. PCRE, to forbid the previous char you could use negative lookbehind, but unfortunately Javascript regex does not support it.

So, to circumvent this, we must:

  • Put a capturing group matching either start of text or something other than a digit: (^|\D).
  • Then put regex matching just 2: 2.

The last condition, fortunately, can be expressed as negative lookahead, because even Javascript regex support it: (?!\d).

So the whole regex is:

(^|\D)2(?!\d)

Having found such a match, you have to replace it with the content of the first capturing group and 3 (the replacement digit).

Upvotes: 3

trincot
trincot

Reputation: 350272

You can use negative look-ahead:

(\D|^)2(?!\d)

Replace with: ${1}3

If look behind is supported:

(?<!\d)2(?!\d)

Replace with: 3

Upvotes: 2

Related Questions