Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to replace captured groups only?

I have HTML code before and after the string:

name="some_text_0_some_text" 

I would like to replace the 0 with something like : !NEW_ID!

So I made a simple regex :

.*name="\w+(\d+)\w+".* 

But I don't see how to replace exclusively the captured block.

Is there a way to replace a captured result like ($1) with some other string ?

The result would be :

name="some_text_!NEW_ID!_some_text" 
like image 381
Nicolas Guillaume Avatar asked Oct 17 '10 19:10

Nicolas Guillaume


People also ask

How do you reference a capture group?

Normally, within a pattern, you create a back-reference to the content a capture group previously matched by using a backslash followed by the group number—for instance \1 for Group 1. (The syntax for replacements can vary.)

How do you substitute in regex?

To perform a substitution, you use the Replace method of the Regex class, instead of the Match method that we've seen in earlier articles. This method is similar to Match, except that it includes an extra string parameter to receive the replacement value.

Can I use named capture groups?

Numbers for Named Capturing Groups. Mixing named and numbered capturing groups is not recommended because flavors are inconsistent in how the groups are numbered. If a group doesn't need to have a name, make it non-capturing using the (?:group) syntax.

What does a non-capturing group mean?

Non-capturing groups are important constructs within Java Regular Expressions. They create a sub-pattern that functions as a single unit but does not save the matched character sequence.


2 Answers

A solution is to add captures for the preceding and following text:

str.replace(/(.*name="\w+)(\d+)(\w+".*)/, "$1!NEW_ID!$3") 
like image 172
Matthew Flaschen Avatar answered Sep 18 '22 14:09

Matthew Flaschen


Now that Javascript has lookbehind (as of ES2018), on newer environments, you can avoid groups entirely in situations like these. Rather, lookbehind for what comes before the group you were capturing, and lookahead for what comes after, and replace with just !NEW_ID!:

const str = 'name="some_text_0_some_text"'; console.log(   str.replace(/(?<=name="\w+)\d+(?=\w+")/, '!NEW_ID!') );

With this method, the full match is only the part that needs to be replaced.

  • (?<=name="\w+) - Lookbehind for name=", followed by word characters (luckily, lookbehinds do not have to be fixed width in Javascript!)
  • \d+ - Match one or more digits - the only part of the pattern not in a lookaround, the only part of the string that will be in the resulting match
  • (?=\w+") - Lookahead for word characters followed by " `

Keep in mind that lookbehind is pretty new. It works in modern versions of V8 (including Chrome, Opera, and Node), but not in most other environments, at least not yet. So while you can reliably use lookbehind in Node and in your own browser (if it runs on a modern version of V8), it's not yet sufficiently supported by random clients (like on a public website).

like image 22
CertainPerformance Avatar answered Sep 18 '22 14:09

CertainPerformance