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

Converting user input string to regular expression

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

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


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

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


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

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


使用javascript regexp对象构造函数。

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

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


这里有一条线:str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')

我是从escape string regexp npm模块得到的。

试一试:

1
2
3
4
5
6
7
escapeStringRegExp.matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
function escapeStringRegExp(str) {
    return str.replace(escapeStringRegExp.matchOperatorsRe, '\\$&');
}

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

在我的例子中,用户输入的某些部分被分隔符舍入,有时不是。因此,我又增加了一个案例。

1
2
3
4
5
6
7
8
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);
}


当字符串无效或不包含标志等时,这也会起作用:

1
2
3
4
5
6
7
8
9
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'));


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

为什么?因为否则一些用户会添加//,而其他用户不会。有些会产生语法错误。然后,在剥离//后,您可能最终得到一个语法上有效的regex,它与用户的意图完全不同,从而导致奇怪的行为(从用户的角度来看)。


多亏了前面的答案,这个块还可以作为将可配置字符串应用到regex中的通用解决方案。过滤文本:

1
2
3
4
5
6
7
8
9
10
11
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, '');

如果确实要将字符串转换为regex,请尝试使用以下函数:

1
function String2Regex(s){return new RegExp(s.match(/\/(.+)\/.*/)[1], s.match(/\/.+\/(.*)/)[1]);}

你可以这样使用它:

1
2
"abc".match(String2Regex("/a/g"))
> ["a"]

以下是格式更现代的版本供参考:

1
2
3
4
5
6
7
8
9
10
const String2Regex = str => {
  // Main regex
  const main = str.match(/\/(.+)\/.*/)[1]

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

  // Return compiled regex
  return new RegExp(main, options)
}

您可以使用复选框请求标志,然后执行如下操作:

1
2
3
4
5
var userInput = formInput;
var flags = '';
if(formGlobalCheckboxChecked) flags += 'g';
if(formCaseICheckboxChecked) flags += 'i';
var reg = new RegExp(userInput, flags);