4

How can I create a regex from a variable so that it has a capture group that can then be used in a replace() call?

The below is what I have tried so far without success.

var term = 'test'
var r = new RegExp('('+term+')', "ig");

$('#test').html( $('#test').html().replace(r, '<span class="found">'+$1+'</span>') ); // Uncaught ReferenceError: $1 is not defined
.found{
  background-color:yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="test">This is a test</div>
Wesley Smith
  • 19,401
  • 22
  • 85
  • 133

2 Answers2

4

I guess this is working as you expect? The main thing is to use $1 inside the replacement string, as <span class="found">$1</span>.

var term = 'test'
var r = new RegExp('('+term+')', "ig");

$('#test').html( $('#test').html().replace(r, '<span class="found">$1</span>') ); 
.found{
  background-color:yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="test">This is a test</div>

You may also discard the capturing group and use the $& backreference in the string replacement pattern that refers to the whole match and also escape the search string since in case it contains special regex chars, it may fail to match:

var term = 'test+test'
var r = new RegExp(term.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), "ig");

$('#test').html( $('#test').html().replace(r, '<span class="found">$&</span>') ); 
.found{
  background-color:yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="test">This is a test+test</div>
Wiktor Stribiżew
  • 607,720
  • 39
  • 448
  • 563
  • Yes :). Also, have a look at "Using Parenthesized Substring Matches" at MDN (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions), this is very helpful. – Wiktor Stribiżew Apr 03 '15 at 14:11
  • This approach will fall over if `term` contains any parentheses, so you'll have to escape them with something like `term.replace(/\(/g, "\\(").replace(/\)/g, "\\)")`... and the same for `[]` and of course \ itself. See this answer for a general solution to regex term sanitising (https://codereview.stackexchange.com/a/153702). – Extragorey May 28 '19 at 02:43
  • @Extragorey I can't see how your comment is relevant: my second code snippet shows exactly how to deal with special characters (*`var r = new RegExp(term.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), "ig");`*). This question was basically about replacing a regex match with itself, escaping special chars was an additional enhancement in case OP had to deal with special characters. It is not always the case. – Wiktor Stribiżew May 28 '19 at 06:55
  • @WiktorStribiżew All good, just thought I'd enhance the answer for people like me who need it. – Extragorey May 29 '19 at 13:01
  • @Extragorey Then the codereview link can be replaced with an [SO link](https://stackoverflow.com/a/3561711/3832970), I consider that escaping code the cleanest. – Wiktor Stribiżew May 29 '19 at 13:20
1

You need to wrap replace expression with a function.

var term = 'test'
var r = new RegExp('('+term+')', "ig");

$('#test').html( $('#test').html().replace(r, function($1){return '<span class="found">'+$1+'</span>'}) ); // Uncaught ReferenceError: $1 is not defined
.found{
  background-color:yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="test">This is a test</div>
Yury Tarabanko
  • 44,270
  • 9
  • 84
  • 98