RegExp exec - string manipulation

I have a string that I am trying to manipulate using a regular expression as follows:

var str = 'This is a string with 1: {{param1}}, 2: {{param2}} and 3: {{param3}}', reg = /{{.*?}}/ig; while (field = reg.exec(str)) { str = str.replace(field, 'test'); } 

{{param2}} never replaced, because I assume that I am manipulating the string when it is run through RegExp.exec(...) . But can not be sure.

I tried the following (since I noticed that RegExp.exec(...) returns an array) - still no luck:

 var str = 'This is a string with 1: {{param1}}, 2: {{param2}} and 3: {{param3}}', reg = /{{.*?}}/ig; while (field = reg.exec(str)) { str = str.replace(field[0], 'test'); } 

Any ideas?

Edit: current result of this function:

 'This is a string with 1: test, 2: {{param2}}, test and 3: test' 
+5
source share
3 answers

You must remove the g flag.

 var str = 'This is a string with 1: {{param1}}, 2: {{param2}} and 3: {{param3}}', reg = /{{.*?}}/; while (field = reg.exec(str)) { str = str.replace(field, 'test'); console.log(str) } 

Result:

First iteration:

This is a line with 1: test, 2: {{param2}} and 3: {{param3}}

The second:

This is the line with test 1: test, 2: test and 3: {{param3}}

third:

This is the line with test 1: test, 2: test and 3: test

Another variant:

  str = str.replace(/{{.*?}}/g, 'test'); 

This will also give:

This is the line with test 1: test, 2: test and 3: test

Edit:

To add an anonymous answer:

The problem is that each replace makes the original line shorter. Indexes were calculated at the beginning with the original longer string.

In other words, if you wanted to replace an expression of the same length as {{param1}} (whose length is 9) with another line with the same length of 9, say: **test1** , then your code would work:

 var str = 'This is a string with 1: {{param1}}, 2: {{param2}} and 3: {{param3}}', reg = /{{.*?}}/g while (field = reg.exec(str)) { str = str.replace(field, '**test1**'); console.log(str) } 

Result:

This is a string with 1: **test1**, 2: **test1** and 3: **test1**

+3
source

I would suggest using String#replace by providing a function:

 var text = 'This is a string with 1: {{param1}}, 2: {{param2}} and 3: {{param3}}'; var result = text.replace(/{{.*?}}/g, function (match) { // *match* contains the full match, if you have captures // then they will be handed in as additional arguments return 'test'; }); 

In my opinion, this is much cleaner than messing around with indexes, etc. Check out this script for the working version.

+1
source

You're right. Because of the replacement, it is barely enough. The following is the regular expression execution order:

  • After the first exec reg.lastIndex set to 35.
  • The rest of the line to check then becomes ', 2: {{param2}} and 3: {{param3}}'
  • After the first replacement, the remaining line will be '{param2}} and 3: {{param3}}' , since lastIndex will not change from 35.
  • The next iteration of regular expression matching occurs, but it does not match {param2}} , so it remains matching until it reaches '{{param3}}' .

All this is due to the fact that the g lobal regex flag saves lastIndex . Instead, you can remove the global flag to automatically set lastIndex to 0 after the completion of one match. However, this means that the regular expression will always start from the beginning. The best option is to install lastIndex in the right place.

 var str = 'This is a string with 1: {{param1}}, 2: {{param2}} and 3: {{param3}}', reg = /{{.*?}}/ig, replacement = 'test'; while (field = reg.exec(str)) { str = str.replace(field[0], replacement); reg.lastIndex = reg.lastIndex - field[0].length + replacement.length; } console.log(str); 
0
source

All Articles