将用户输入字符串转换为正则表达式

我正在用HTML和JavaScript设计一个正则表达式测试器。用户将输入一个正则表达式,一个字符串,并通过单选按钮选择他们想要测试的函数(例如搜索,匹配,替换等),当该函数以指定的参数运行时,程序将显示结果。自然会有额外的文本框用于替换额外的参数等等。

我的问题是从用户获取字符串并将其转换为正则表达式。如果我说它们不需要在输入的正则表达式周围有//,那么它们就不能设置标记,比如gi。所以它们必须在表达式周围有//,但我如何将该字符串转换为正则表达式?它不能是一个字面量,因为它是一个字符串,我不能将它传递给RegExp构造函数,因为它不是一个没有//的字符串。有没有其他方法让用户输入字符串到正则表达式?我必须用//解析正则表达式的字符串和标志,然后以另一种方式构造它吗?我应该让他们输入一个字符串,然后分别输入标志吗?

382522 次浏览

使用JavaScript RegExp对象构造函数

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

可以将标志作为第二个字符串参数传递给构造函数。详细信息请参见文档。

使用RegExp对象构造函数从字符串创建正则表达式:

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

我建议您还为特殊标志添加单独的复选框或文本框。这样就很清楚用户不需要添加任何//。在replace的情况下,提供两个文本字段。这会让你的生活轻松很多。

为什么?因为否则一些用户会添加//,而其他用户不会。有些会犯语法错误。然后,在你剥离//之后,你可能会得到一个语法上有效的正则表达式,它与用户想要的完全不同,导致奇怪的行为(从用户的角度来看)。

你可以使用复选框来请求标志,然后做这样的事情:

var userInput = formInput;
var flags = '';
if(formGlobalCheckboxChecked) flags += 'g';
if(formCaseICheckboxChecked) flags += 'i';
var reg = new RegExp(userInput, flags);
var flags = inputstring.replace(/.*\/([gimy]*)$/, '$1');
var pattern = inputstring.replace(new RegExp('^/(.*?)/'+flags+'$'), '$1');
var regex = new RegExp(pattern, flags);

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

在我的例子中,用户输入有时被分隔符包围,有时没有。所以我又加了一个案例。

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);
}

感谢前面的回答,这个块作为一个通用的解决方案应用一个可配置的字符串到RegEx ..过滤文本:

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, '');

下面是一行代码:str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')

我从escape-string-regexp NPM模块中得到它。

尝试一下:

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


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

使用带标记的模板文字支持:

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

这也适用于字符串无效或不包含标志等情况:

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'));

尝试使用下面的函数:

const stringToRegex = str => {
// Main regex
const main = str.match(/\/(.+)\/.*/)[1]
    

// Regex options
const options = str.match(/\/.+\/(.*)/)[1]
    

// Compiled regex
return new RegExp(main, options)
}

你可以这样使用它:

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

我使用eval来解决这个问题。

例如:

    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()));
}

下面是一个处理自定义分隔符和无效标志的线性函数

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


// Readable version
function stringToRegex(str) {
const match = str.match(/^([\/~@;%#'])(.*?)\1([gimsuy]*)$/);
return match ?
new RegExp(
match[2],
match[3]
// Filter redundant flags, to avoid exceptions
.split('')
.filter((char, pos, flagArr) => flagArr.indexOf(char) === pos)
.join('')
)
: new RegExp(str);
}


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

安全了,但也不安全。(一个不能访问任何其他上下文的函数版本会很好。)

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