Converting user input string to regular expression

JavascriptHtmlRegex

Javascript Problem Overview


I am designing a regular expression tester in HTML and JavaScript. The user will enter a regex, a string, and choose the function they want to test with (e.g. search, match, replace, etc.) via radio button and the program will display the results when that function is run with the specified arguments. Naturally there will be extra text boxes for the extra arguments to replace and such.

My problem is getting the string from the user and turning it into a regular expression. If I say that they don't need to have //'s around the regex they enter, then they can't set flags, like g and i. So they have to have the //'s around the expression, but how can I convert that string to a regex? It can't be a literal since its a string, and I can't pass it to the RegExp constructor since its not a string without the //'s. Is there any other way to make a user input string into a regex? Will I have to parse the string and flags of the regex with the //'s then construct it another way? Should I have them enter a string, and then enter the flags separately?

Javascript Solutions


Solution 1 - Javascript

Use the RegExp object constructor to create a regular expression from a string:

var re = new RegExp("a|b", "i");
// same as
var re = /a|b/i;

Solution 2 - Javascript

var flags = inputstring.replace(/.*\/([gimy]*)$/, '$1');
var pattern = inputstring.replace(new RegExp('^/(.*?)/'+flags+'$'), '$1');
var regex = new RegExp(pattern, flags);

or

var match = inputstring.match(new RegExp('^/(.*?)/([gimy]*)$'));
// sanity check here
var regex = new RegExp(match[1], match[2]);

Solution 3 - Javascript

Here is a one-liner: str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')

I got it from the escape-string-regexp NPM module.

Trying it out:

escapeStringRegExp.matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
function escapeStringRegExp(str) {
    return str.replace(escapeStringRegExp.matchOperatorsRe, '\\$&');
}

console.log(new RegExp(escapeStringRegExp('example.com')));
// => /example\.com/

Using tagged template literals with flags support:

function str2reg(flags = 'u') {
	return (...args) => new RegExp(escapeStringRegExp(evalTemplate(...args))
		, flags)
}

function evalTemplate(strings, ...values) {
	let i = 0
	return strings.reduce((str, string) => `${str}${string}${
		i < values.length ? values[i++] : ''}`, '')
}

console.log(str2reg()`example.com`)
// => /example\.com/u

Solution 4 - Javascript

Use the JavaScript RegExp object constructor.

var re = new RegExp("\\w+");
re.test("hello");

You can pass flags as a second string argument to the constructor. See the documentation for details.

Solution 5 - Javascript

In my case the user input somethimes was sorrounded by delimiters and sometimes not. therefore I added another case..

var regParts = inputstring.match(/^\/(.*?)\/([gim]*)$/);
if (regParts) {
    // the parsed pattern had delimiters and modifiers. handle them. 
    var regexp = new RegExp(regParts[1], regParts[2]);
} else {
    // we got pattern string without delimiters
    var regexp = new RegExp(inputstring);
}

Solution 6 - Javascript

Try using the following function:

const stringToRegex = str => {
    // Main regex
    const main = str.match(/\/(.+)\/.*/)[1]
    
    // Regex options
    const options = str.match(/\/.+\/(.*)/)[1]
    
    // Compiled regex
    return new RegExp(main, options)
}

You can use it like so:

"abc".match(stringToRegex("/a/g"))
//=> ["a"]

Solution 7 - Javascript

I suggest you also add separate checkboxes or a textfield for the special flags. That way it is clear that the user does not need to add any //'s. In the case of a replace, provide two textfields. This will make your life a lot easier.

Why? Because otherwise some users will add //'s while other will not. And some will make a syntax error. Then, after you stripped the //'s, you may end up with a syntactically valid regex that is nothing like what the user intended, leading to strange behaviour (from the user's perspective).

Solution 8 - Javascript

Here is my one liner function that handles custom delimiters and invalid flags

function stringToRegex(s, m) {
  return (m = s.match(/^([\/~@;%#'])(.*?)\1([gimsuy]*)$/)) ? new RegExp(m[2], m[3].split('').filter((i, p, s) => s.indexOf(i) === p).join('')) : new RegExp(s);
}

console.log(stringToRegex('/(foo)?\/bar/i'));
console.log(stringToRegex('#(foo)?\/bar##gi')); //Custom delimiters
console.log(stringToRegex('#(foo)?\/bar##gig')); //Duplicate flags are filtered out
console.log(stringToRegex('/(foo)?\/bar')); // Treated as string
console.log(stringToRegex('gig')); // Treated as string

Solution 9 - Javascript

This will work also when the string is invalid or does not contain flags etc:

function regExpFromString(q) {
  let flags = q.replace(/.*\/([gimuy]*)$/, '$1');
  if (flags === q) flags = '';
  let pattern = (flags ? q.replace(new RegExp('^/(.*?)/' + flags + '$'), '$1') : q);
  try { return new RegExp(pattern, flags); } catch (e) { return null; }
}

console.log(regExpFromString('\\bword\\b'));
console.log(regExpFromString('\/\\bword\\b\/gi'));
            

Solution 10 - Javascript

You can ask for flags using checkboxes then do something like this:

var userInput = formInput;
var flags = '';
if(formGlobalCheckboxChecked) flags += 'g';
if(formCaseICheckboxChecked) flags += 'i';
var reg = new RegExp(userInput, flags);

Solution 11 - Javascript

Thanks to earlier answers, this blocks serves well as a general purpose solution for applying a configurable string into a RegEx .. for filtering text:

var permittedChars = '^a-z0-9 _,.?!@+<>';
permittedChars = '[' + permittedChars + ']';

var flags = 'gi';
var strFilterRegEx = new RegExp(permittedChars, flags);

log.debug ('strFilterRegEx: ' + strFilterRegEx);

strVal = strVal.replace(strFilterRegEx, '');
// this replaces hard code solt:
// strVal = strVal.replace(/[^a-z0-9 _,.?!@+]/ig, '');

Solution 12 - Javascript

Safer, but not safe. (A version of Function that didn't have access to any other context would be good.)

const regexp = Function('return ' + string)()

Solution 13 - Javascript

I use eval to solve this problem.

For example:

    function regex_exec() {

        // Important! Like @Samuel Faure mentioned, Eval on user input is a crazy security risk, so before use this method, please take care of the security risk. 
        var regex = $("#regex").val();

        // eval()
        var patt = eval(userInput);

        $("#result").val(patt.exec($("#textContent").val()));
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGordon GustafsonView Question on Stackoverflow
Solution 1 - JavascriptGumboView Answer on Stackoverflow
Solution 2 - JavascriptAnonymousView Answer on Stackoverflow
Solution 3 - JavascriptRivenfallView Answer on Stackoverflow
Solution 4 - JavascriptAyman HouriehView Answer on Stackoverflow
Solution 5 - JavascriptstaabmView Answer on Stackoverflow
Solution 6 - JavascriptRichie BendallView Answer on Stackoverflow
Solution 7 - JavascriptStephan202View Answer on Stackoverflow
Solution 8 - JavascriptTofandelView Answer on Stackoverflow
Solution 9 - JavascriptkofifusView Answer on Stackoverflow
Solution 10 - JavascriptPim JagerView Answer on Stackoverflow
Solution 11 - JavascriptGene BoView Answer on Stackoverflow
Solution 12 - JavascriptStephen ToddView Answer on Stackoverflow
Solution 13 - JavascriptPlayhiView Answer on Stackoverflow