How do you use a variable in a regular expression?
Asked Answered
A

28

1925

I would like to create a String.replaceAll() method in JavaScript and think using a regex would be the most terse way to do it. However, I can't figure out how to pass a variable into a regex. I can do this already which will replace all the instances of "B" with "A".

"ABABAB".replace(/B/g, "A");

But I want to do something like this:

String.prototype.replaceAll = function(replaceThis, withThis) {
    this.replace(/replaceThis/g, withThis);
};

But obviously, this will only replace the text "replaceThis"...so how do I pass this variable into my regex string?

Anterior answered 30/1, 2009 at 0:11 Comment(2)
Note that we're currently working on adding this functionality to JavaScript if you have an opinion about it please join the discussion.Ultraism
const re = new RegExp(`${replaceThis}`, 'g'); str.replace(re, withThis);Kinnikinnick
V
2389

Instead of using the /regex\d/g syntax, you can construct a new RegExp object:

var replace = "regex\\d";
var re = new RegExp(replace,"g");

You can dynamically create regex objects this way. Then you will do:

"mystring1".replace(re, "newstring");
Voltmer answered 30/1, 2009 at 0:15 Comment(3)
If you need to use an expression like /\/word\:\w*$/, be sure to escape your backslashes: new RegExp( '\\/word\\:\\w*$' ).Agreeable
The question suggests that the RegEx is only used to do a constant string replacement. So this is answer is wrong as it would fail if the string contains RegEx meta characters. Sad it is voted this high, will make many headaches...Skiing
An example of this passing a variable would make this a good answer. I'm still struggling after reading this.Cypress
M
280

As Eric Wendelin mentioned, you can do something like this:

str1 = "pattern"
var re = new RegExp(str1, "g");
"pattern matching .".replace(re, "regex");

This yields "regex matching .". However, it will fail if str1 is ".". You'd expect the result to be "pattern matching regex", replacing the period with "regex", but it'll turn out to be...

regexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregexregex

This is because, although "." is a String, in the RegExp constructor it's still interpreted as a regular expression, meaning any non-line-break character, meaning every character in the string. For this purpose, the following function may be useful:

 RegExp.quote = function(str) {
     return str.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
 };

Then you can do:

str1 = "."
var re = new RegExp(RegExp.quote(str1), "g");
"pattern matching .".replace(re, "regex");

yielding "pattern matching regex".

Mehalick answered 30/1, 2009 at 1:2 Comment(10)
You know that the first parameter to replace can be a normal string and don't have to be a regexp? str1 = "."; alert("pattern matching .".replace(str1, "string"));Periphrastic
@some: of course. That's because the above example is trivial. When you need to search for or replace a pattern combined with a regular string, do str.match(new RegExp("https?://" + RegExp.escape(myDomainName)), for instance. It's annoying that the escape function is not built in.Mehalick
(continued) Plus, apparentl JC Grubbs required a global replace; implementing a global replace with String.replace(String, String) could be slow for large input. I'm just saying, the top two solutions are buggy, and will fail unexpected on certain input.Mehalick
developer.mozilla.org/en-US/docs/JavaScript/Guide/… offers a similar function, but they exclude -, and include =!:/.Bracketing
The correct term is "escape", not "quote". Just BTW.Asymmetry
Lodash has escapeRegExp for this - lodash.com/docs#escapeRegExpRobinett
Would /[^\w\s]/g be a safe alternative to /([.?*+^$[\]\\(){}|-])/g?Male
@LawrenceDol Actually, both are acceptable. Bash and Lisp programmers often talk about quoting expressions, while most string manipulation code talks about escape sequences. Backslash quotes or escapes the following character, enabling literal or special treatmentThirion
I want to use a loop, but it does nothing: for (reg of regs) { var re = new RegExp(reg, "g");bodyPost.replace(re, '') }Dunkirk
Indeed, why do you escape -?..Psychometrics
D
150

"ABABAB".replace(/B/g, "A");

As always: don't use regex unless you have to. For a simple string replace, the idiom is:

'ABABAB'.split('B').join('A')

Then you don't have to worry about the quoting issues mentioned in Gracenotes's answer.

Decisive answered 1/2, 2009 at 3:43 Comment(10)
And have you measured that this is faster than regex?Mylesmylitta
This seems preferable, especially when needing to match on special regex characters like '.'Hindemith
Uhm... Doesn't split take a RegExp too; if so, wouldn't it cause the same problem ? Anyway... .split().join() may be slower on some platforms, because it's two operations, whereas .replace() is one operation and may be optimized.Halleyhalli
@PacMan--: both split and replace can take either a string or a RegExp object. The problem that replace has that split doesn't is that when you use a string you only get a single replacement.Decisive
Could someone have a basic benchmark of their respective performance?Mistrust
benchmark here: jsperf.com/replace-vs-split-join-vs-replaceall/23Frictional
It's an okay point of view, but the question is explicitly about how to use variable names in regex, not about what you can use instead of regex.Unthrone
"otherwise they have no discernible benefit" You don't consider making your code damn-near unreadable to be a benefit?Attitudinarian
If a regular expression is written well it should be readable. There are cases like email addresses & home addresses, but those are unavoidable and can only be handled by RE. Usually if the regex is complex, its because it is a complex problem, and regex offers the best solution. If the problem is not complex, and another solution could be implimented, in most cases it will be easy to solve with RE, which means if the author knows how to write good regex, the pattern should be very readable.Odor
Sorry to have to downvote, but there must be a limit to che convolution of our code. Correctly written regex are a readable, mature, professional feature of our beloved language. I disagree completely with the statement "don't use regex unless you have to".Whittling
P
146

If you want to get all occurrences (g), be case insensitive (i), and use boundaries so that it isn't a word within another word (\\b):

re = new RegExp(`\\b${replaceThis}\\b`, 'gi');

let inputString = "I'm John, or johnny, but I prefer john.";
let replaceThis = "John";
let re = new RegExp(`\\b${replaceThis}\\b`, 'gi');
console.log(inputString.replace(re, "Jack"));
Palaeozoic answered 13/6, 2018 at 2:52 Comment(5)
thank you! (afaict, yours is the only answer explicitly with Emacs/rx-style interpolation, via template strings.)Shuping
What about replaceAll? Would it work the same as replace with the global flag?Rianna
@Rianna technically you could use replaceAll with the exact regex above (including global flag) - but it would have no benefit. You would get an error if you tried to use it without the global flag, see this.Palaeozoic
hi i'm trying to use this but not working 'const regex = new RegExp(/(?=.{\\b${digits}\\b}).*/g);' whereas digits is a numeric variable I'm passing down as a parameter. If possible can u explain how can I fix this?Thorbert
@Thorbert integers work fine when I test them with my current example. Please create a separate question with a minimal reproducible example.Palaeozoic
L
44

This:

var txt=new RegExp(pattern,attributes);

is equivalent to this:

var txt=/pattern/attributes;

See http://www.w3schools.com/jsref/jsref_obj_regexp.asp.

Lave answered 30/1, 2009 at 0:19 Comment(1)
yep, but in first example it uses pattern as variable, in 2nd as a stringTetraspore
H
40

For anyone looking to use a variable with the match method, this worked for me:

var alpha = 'fig';
'food fight'.match(alpha + 'ht')[0]; // fight
Hexyl answered 28/11, 2012 at 15:32 Comment(0)
A
37
this.replace( new RegExp( replaceThis, 'g' ), withThis );
Alarise answered 30/1, 2009 at 0:16 Comment(1)
I like this answer as it doesn't create the extra (& pointless) variable.Enthronement
C
24

You need to build the regular expression dynamically and for this you must use the new RegExp(string) constructor with escaping.

There is a built-in function in jQuery UI autocomplete widget called $.ui.autocomplete.escapeRegex:

It'll take a single string argument and escape all regex characters, making the result safe to pass to new RegExp().

If you are not using jQuery UI you can copy its definition from the source:

function escapeRegex( value ) {
    return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
}

And use it like this:

"[z-a][z-a][z-a]".replace(new RegExp(escapeRegex("[z-a]"), "g"), "[a-z]");
//            escapeRegex("[z-a]")       -> "\[z\-a\]"
// new RegExp(escapeRegex("[z-a]"), "g") -> /\[z\-a\]/g
// end result                            -> "[a-z][a-z][a-z]"
Craven answered 14/9, 2014 at 19:55 Comment(0)
G
10
String.prototype.replaceAll = function (replaceThis, withThis) {
   var re = new RegExp(replaceThis,"g"); 
   return this.replace(re, withThis);
};
var aa = "abab54..aba".replaceAll("\\.", "v");

Test with this tool

Gumma answered 1/2, 2009 at 9:14 Comment(0)
P
7

You can use a string as a regular expression. Don’t forget to use new RegExp.

Example:

var yourFunction = new RegExp(
        '^-?\\d+(?:\\.\\d{0,' + yourVar + '})?'
      )
Pulsatory answered 22/3, 2021 at 23:52 Comment(0)
D
6
String.prototype.replaceAll = function(a, b) {
    return this.replace(new RegExp(a.replace(/([.?*+^$[\]\\(){}|-])/ig, "\\$1"), 'ig'), b)
}

Test it like:

var whatever = 'Some [b]random[/b] text in a [b]sentence.[/b]'

console.log(whatever.replaceAll("[", "<").replaceAll("]", ">"))
Dictionary answered 20/8, 2013 at 12:35 Comment(0)
L
5

To satisfy my need to insert a variable/alias/function into a Regular Expression, this is what I came up with:

oldre = /xx\(""\)/;
function newre(e){
    return RegExp(e.toString().replace(/\//g,"").replace(/xx/g, yy), "g")
};

String.prototype.replaceAll = this.replace(newre(oldre), "withThis");

where 'oldre' is the original regexp that I want to insert a variable, 'xx' is the placeholder for that variable/alias/function, and 'yy' is the actual variable name, alias, or function.

Liliuokalani answered 5/6, 2013 at 4:22 Comment(1)
After trying every single solution for inserting a variable inside the regular expression, yours was the only one that worked for me. Thank you sooo much!Euphuism
Z
5

And the CoffeeScript version of Steven Penny's answer, since this is #2 Google result....even if CoffeeScript is just JavaScript with a lot of characters removed...;)

baz = "foo"
filter = new RegExp(baz + "d")
"food fight".match(filter)[0] // food

And in my particular case:

robot.name = hubot
filter = new RegExp(robot.name)
if msg.match.input.match(filter)
  console.log "True!"
Zamudio answered 25/11, 2014 at 23:31 Comment(2)
why a downvote? coffeescript -IS- javascript with it's own specific syntax.Zamudio
robot.name=hubot is not javascript.Plurality
M
4

Here's another replaceAll implementation:

    String.prototype.replaceAll = function (stringToFind, stringToReplace) {
        if ( stringToFind == stringToReplace) return this;
        var temp = this;
        var index = temp.indexOf(stringToFind);
        while (index != -1) {
            temp = temp.replace(stringToFind, stringToReplace);
            index = temp.indexOf(stringToFind);
        }
        return temp;
    };
Membrane answered 8/5, 2013 at 10:30 Comment(0)
L
4

You can use this if $1 does not work for you:

var pattern = new RegExp("amman", "i");
"abc Amman efg".replace(pattern, "<b>" + "abc Amman efg".match(pattern)[0] + "</b>");
Lampe answered 13/6, 2013 at 11:13 Comment(0)
O
3

While you can make dynamically-created RegExp's (as per the other responses to this question), I'll echo my comment from a similar post: The functional form of String.replace() is extremely useful and in many cases reduces the need for dynamically-created RegExp objects. (which are kind of a pain 'cause you have to express the input to the RegExp constructor as a string rather than use the slashes /[A-Z]+/ regexp literal format)

Odericus answered 30/1, 2009 at 1:2 Comment(0)
T
3

None of these answers were clear to me. I eventually found a good explanation at How to use a variable in replace function of JavaScript

The simple answer is:

var search_term = new RegExp(search_term, "g");
text = text.replace(search_term, replace_term);

For example:

$("button").click(function() {
  Find_and_replace("Lorem", "Chocolate");
  Find_and_replace("ipsum", "ice-cream");
});

function Find_and_replace(search_term, replace_term) {
  text = $("textbox").html();
  var search_term = new RegExp(search_term, "g");
  text = text.replace(search_term, replace_term);
  $("textbox").html(text);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textbox>
  Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum Lorem ipsum
</textbox>
<button>Click me</button>
Trotyl answered 18/10, 2018 at 18:37 Comment(1)
You're overwriting a closure variable, no need to use var here. Also, if you pass \b or \1 it would break.Intersex
I
3

This self calling function will iterate over replacerItems using an index, and change replacerItems[index] globally on the string with each pass.

  const replacerItems = ["a", "b", "c"];    

    function replacer(str, index){
          const item = replacerItems[index];
          const regex = new RegExp(`[${item}]`, "g");
          const newStr = str.replace(regex, "z");
          if (index < replacerItems.length - 1) {
            return replacer(newStr, index + 1);
          }
          return newStr;
    }

// console.log(replacer('abcdefg', 0)) will output 'zzzdefg'
Irremovable answered 16/12, 2019 at 17:24 Comment(0)
O
3

I found so many answers with weird examples in here and in other open tickets on stackoverflow or similar forums.

This is the simplest option in my opinion how u can put variable as template literal string;

const someString = "abc";
const regex = new RegExp(`^ someregex ${someString} someregex $`);

As u can see I'm not puting forward slash at the beginning or the end, the RegExp constructor will reconstruct the valid regex literal. Works with yup matches function also.

Oliviaolivie answered 15/8, 2022 at 8:55 Comment(1)
youre not using slash, but youre using a backtick? Maybe you can explain this.Bookseller
H
2

You can always use indexOf repeatedly:

String.prototype.replaceAll = function(substring, replacement) {
    var result = '';
    var lastIndex = 0;

    while(true) {
        var index = this.indexOf(substring, lastIndex);
        if(index === -1) break;
        result += this.substring(lastIndex, index) + replacement;
        lastIndex = index + substring.length;
    }

    return result + this.substring(lastIndex);
};

This doesn’t go into an infinite loop when the replacement contains the match.

Humidity answered 16/8, 2013 at 19:53 Comment(0)
D
2

One way to implement is by taking the value from a text field which is the one you want to replace and another is the "replace with" text field, getting the value from text-field in a variable and setting the variable to RegExp function to further replace. In my case I am using jQuery, but you can also do it by only JavaScript too.

JavaScript code:

  var replace =document.getElementById("replace}"); // getting a value from a text field with I want to replace
  var replace_with = document.getElementById("with"); //Getting the value from another text fields with which I want to replace another string.

  var sRegExInput = new RegExp(replace, "g");
  $("body").children().each(function() {
    $(this).html($(this).html().replace(sRegExInput,replace_with));
  });

This code is on the Onclick event of a button, and you can put this in a function to call.

So now you can pass a variable in the replace function.

Dorothadorothea answered 27/10, 2015 at 5:56 Comment(3)
Your replace_with variable will contain the DOM element not the value itselfExpiable
The link is broken: "Page not found - Mindfire Solutions. 404. Looks like you are lost."Ratiocination
Just ignor the link you can use the code given in the answer it should work accordinglyDorothadorothea
B
1

example: regex start with

function startWith(char, value) {
    return new RegExp(`^[${char}]`, 'gi').test(value);
}
Blastosphere answered 1/8, 2022 at 9:55 Comment(0)
T
1

Easy method:

String.prototype.replaceAll = function(replaceThis, withThis) {
    const regexp = new RegExp(`${replaceThis}`, 'g');
    this.replace(regexp, withThis);
};
Terraqueous answered 18/11, 2023 at 12:14 Comment(0)
D
0

For multiple replace without regular expressions I went with the following:

      let str = "I am a cat man. I like cats";
      let find = "cat";
      let replace = "dog";


      // Count how many occurrences there are of the string to find 
      // inside the str to be examined.
      let findCount = str.split(find).length - 1;

      let loopCount = 0;

      while (loopCount < findCount) 
      {
        str = str.replace(find, replace);
        loopCount = loopCount + 1;
      }  

      console.log(str);
      // I am a dog man. I like dogs

The important part of the solution was found here

Dignify answered 24/11, 2019 at 1:46 Comment(0)
G
0

As a relative JavaScript novice, the accepted answer https://mcmap.net/q/45039/-how-do-you-use-a-variable-in-a-regular-expression is noted / appreciated, but it is not very intuitive.

Here is a simpler interpretation, by example (using a simple JavaScript IDE).

myString = 'apple pie, banana loaf';

console.log(myString.replaceAll(/pie/gi, 'PIE'))
// apple PIE, banana loaf

console.log(myString.replaceAll(/\bpie\b/gi, 'PIE'))
// apple PIE, banana loaf

console.log(myString.replaceAll(/pi/gi, 'PIE'))
// apple PIEe, banana loaf

console.log(myString.replaceAll(/\bpi\b/gi, 'PIE'))
// [NO EFFECT] apple pie, banana loaf

const match_word = 'pie';

console.log(myString.replaceAll(/match_word/gi, '**PIE**'))
// [NO EFFECT] apple pie, banana loaf

console.log(myString.replaceAll(/\b`${bmatch_word}`\b/gi, '**PIE**'))
// [NO EFFECT] apple pie, banana loaf

// ----------------------------------------
// ... new RegExp(): be sure to \-escape your backslashes: \b >> \\b ...

const match_term = 'pie';
const match_re = new RegExp(`(\\b${match_term}\\b)`, 'gi')

console.log(myString.replaceAll(match_re, 'PiE'))
// apple PiE, banana loaf

console.log(myString.replace(match_re, '**PIE**'))
// apple **PIE**, banana loaf

console.log(myString.replaceAll(match_re, '**PIE**'))
// apple **PIE**, banana loaf

Application

E.g.: replacing (color highlighting) words in string / sentence, [optionally] if the search term matches a more than a user-defined proportion of the matched word.

Note: original character case of matched term is retained. hl: highlight; re: regex | regular expression

mySentence = "Apple, boOk? BOoks; booKEd. BookMark, 'BookmarkeD', bOOkmarks! bookmakinG, Banana; bE, BeEn, beFore."

function replacer(mySentence, hl_term, hl_re) {
    console.log('mySentence [raw]:', mySentence)
    console.log('hl_term:', hl_term, '| hl_term.length:', hl_term.length)
    cutoff = hl_term.length;
    console.log('cutoff:', cutoff)

    // `.match()` conveniently collects multiple matched items
    // (including partial matches) into an [array]
    const hl_terms  = mySentence.toLowerCase().match(hl_re, hl_term);
    if (hl_terms == null) {
        console.log('No matches to hl_term "' + hl_term + '"; echoing input string then exiting ...')
        return mySentence;
    }
    console.log('hl_terms:', hl_terms)
    for (let i = 0;  i < hl_terms.length; i++) {
        console.log('----------------------------------------')
        console.log('[' + i + ']:', hl_terms[i], '| length:', hl_terms[i].length, '| parseInt(0.7(length)):', parseInt(0.7*hl_terms[i].length))
        // TEST: if (hl_terms[i].length >= cutoff*10) {
        if (cutoff >= parseInt(0.7 * hl_terms[i].length)) {
            var match_term = hl_terms[i].toString();

            console.log('matched term:', match_term, '[cutoff length:', cutoff, '| 0.7(matched term length):', parseInt(0.7 * hl_terms[i].length))

            const match_re = new RegExp(`(\\b${match_term}\\b)`, 'gi')

            mySentence = mySentence.replaceAll(match_re, '<font style="background:#ffe74e">$1</font>');
        }
        else {
            var match_term = hl_terms[i].toString();
            console.log('NO match:', match_term, '[cutoff length:', cutoff, '| 0.7(matched term length):', parseInt(0.7 * hl_terms[i].length))
        }
    }
    return mySentence;
}

// TESTS:
// const hl_term = 'be';
// const hl_term = 'bee';
// const hl_term = 'before';
// const hl_term = 'book';
const hl_term = 'bookma';
// const hl_term = 'Leibniz';

// This regex matches from start of word:
const hl_re = new RegExp(`(\\b${hl_term}[A-z]*)\\b`, 'gi')

mySentence = replacer(mySentence, hl_term, hl_re);
console.log('mySentence [processed]:', mySentence)

Output

mySentence [raw]: Apple, boOk? BOoks; booKEd. BookMark, 'BookmarkeD',
bOOkmarks! bookmakinG, Banana; bE, BeEn, beFore.

hl_term: bookma | hl_term.length: 6
cutoff: 6
hl_terms: Array(4) [ "bookmark", "bookmarked", "bookmarks", "bookmaking" ]

----------------------------------------
[0]: bookmark | length: 8 | parseInt(0.7(length)): 5
matched term: bookmark [cutoff length: 6 | 0.7(matched term length): 5
----------------------------------------
[1]: bookmarked | length: 10 | parseInt(0.7(length)): 7
NO match: bookmarked [cutoff length: 6 | 0.7(matched term length): 7
----------------------------------------
[2]: bookmarks | length: 9 | parseInt(0.7(length)): 6
matched term: bookmarks [cutoff length: 6 | 0.7(matched term length): 6
----------------------------------------
[3]: bookmaking | length: 10 | parseInt(0.7(length)): 7
NO match: bookmaking [cutoff length: 6 | 0.7(matched term length): 7

mySentence [processed]: Apple, boOk? BOoks; booKEd.
<font style="background:#ffe74e">BookMark</font>, 'BookmarkeD',
<font style="background:#ffe74e">bOOkmarks</font>! bookmakinG,
Banana; bE, BeEn, beFore.
Gordie answered 10/3, 2021 at 19:29 Comment(0)
V
0

If you pass the variable with the correct syntax, you can do this like so with the code below.

This has the added benefit of using the flags in the same variable.

Also you don't have to double escape \ in the regular expression when it comes to \w, etc.

var str = 'regexVariable example: This is my example of RegExp replacing with a regexVariable.'
var reVar = /(.*?)(regex\w+?iable)(.+?)/gi;
var resStr = str.replace(new RegExp(reVar), '$1 :) :) :) $2 :) :) :)$3');
console.log(resStr);

// Returns:
// :) :) :) regexVariable :) :) :) example: This is my example of RegExp replacing with a  :) :) :) regexVariable :) :) :).

The prototype version as per the OP's example:

var str = 'regexVariable prototype: This is my example of RegExp replacing with a regexVariable.'

String.prototype.regexVariable = function(reFind, reReplace) {
return str.replace(new RegExp(reFind), reReplace);
}

var reVar = /(.*?)(regex\w+?iable)(.+?)/gi;

console.log(str.regexVariable(reVar, '$1 :) :) :) $2 :) :) :)$3'));

// Returns:
// :) :) :) regexVariable :) :) :) prototype: This is my example of replacing with a  :) :) :) regexVariable :) :) :).
Varick answered 21/3, 2021 at 15:30 Comment(0)
L
0

In case anyone else was looking for this, here's how you keep the operators:

// BAD
let foo = "foo"
new RegExp(`${foo}\s`, "g");
// => /foos/g

// GOOD
let foo = "foo"
new RegExp(`${foo}${/\s/.source}`, "g");
// => /foo\s/g
Lastminute answered 17/2, 2023 at 0:54 Comment(0)
X
-1

All these answers seem extremely complicated, when there is a much simpler answer that still gets the job done using regex.

String.prototype.replaceAll = function(replaceThis, withThis) {
    const expr = `${replaceThis}`
    this.replace(new RegExp(expr, "g"), withThis);
};

Explanation

The RegExp constructor takes 2 arguments: the expression, and flags. By using a template string in the expression, we can pass in the variable into the class, and it will transform it to be /(value of the replaceThis variable)/g.

Xray answered 24/8, 2022 at 22:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.