关于正则表达式:Javascript中是否有RegExp.escape函数?

Is there a RegExp.escape function in Javascript?

我只想用任何可能的字符串创建一个正则表达式。

1
2
3
var usersString ="Hello?!*`~World()[]";
var expression = new RegExp(RegExp.escape(usersString))
var matches ="Hello".match(expression);

有内置的方法吗?如果没有,人们会用什么?Ruby有RegExp.escape。我觉得我不需要自己写,那里一定有标准的东西。谢谢!


上面链接的函数不足。它无法退出用于范围的字符组中的^$(字符串的开始和结束)或-

使用此功能:

1
2
3
RegExp.escape= function(s) {
    return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
};

虽然乍一看似乎不需要,但转义-^使函数适合转义插入到字符类和regex主体中的字符。

转义/使函数适合转义在JS regex文本中使用的字符,以便以后进行eval。

由于不存在逃避其中任何一个的不利之处,所以逃避以涵盖更广泛的用例是有意义的。

是的,这不是标准JavaScript的一部分,这是一个令人失望的失败。


对于任何使用lodash的用户,因为v3.0.0 a uuu.escaperegexp函数是内置的:

1
2
_.escapeRegExp('[lodash](https://lodash.com/)');
// → '\[lodash\]\(https:\/\/lodash\.com\/\)'

而且,如果您不想需要完整的lodash库,您可能只需要这个功能!


这里的大多数表达式解决单个特定用例。

没关系,但我更喜欢"总是有效"的方法。

1
2
3
function regExpEscape(literal_string) {
    return literal_string.replace(/[-[\]{}()*+!<=:?.\/\\^$|#\s,]/g, '\\$&');
}

这将"完全转义"用于正则表达式中的以下任何一种用途的文本字符串:

  • 插入正则表达式。如new RegExp(regExpEscape(str))
  • 在字符类中插入。如new RegExp('[' + regExpEscape(str) + ']')
  • 在整数计数说明符中插入。如new RegExp('x{1,' + regExpEscape(str) + '}')
  • 在非javascript正则表达式引擎中执行。

包含的特殊字符:

  • -:在字符类中创建字符范围。
  • [/]:开始/结束字符类。
  • {/}:开始/结束一个数字说明符。
  • (/):开始/结束一个组。
  • */+/?:指定重复类型。
  • .:匹配任何字符。
  • \:转义字符,并启动实体。
  • ^:指定匹配区域的开始,并取消字符类中的匹配。
  • $:指定匹配区域的结束。
  • |:指定变更。
  • #:在自由间距模式下指定注释。
  • \s:在自由间距模式下忽略。
  • ,:分隔数字说明符中的值。
  • /:开始或结束表达式。
  • ::完成特殊的组类型,以及部分Perl风格的字符类。
  • !:否定零宽度组。
  • </=:零宽度组规范的一部分。

笔记:

  • /在任何形式的正则表达式中都不是严格必要的。但是,如果有人(颤抖)做了eval("/" + pattern +"/");,它可以起到保护作用。
  • ,确保如果字符串是数字说明符中的整数,它将正确导致regexp编译错误,而不是静默编译错误。
  • #\s不需要在javascript中进行转义,而是在许多其他类型中进行转义。它们在这里进行转义,以防稍后将正则表达式传递给另一个程序。

如果您还需要对正则表达式进行未来验证,以防止对javascript regex引擎功能的潜在添加,我建议使用更偏执的:

1
2
3
function regExpEscapeFuture(literal_string) {
    return literal_string.replace(/[^A-Za-z0-9_]/g, '\\$&');
}

此函数对每个字符进行转义,除了那些明确保证在以后的正则表达式风格中不用于语法的字符。

对于真正的卫生爱好者,考虑一下这个边缘案例:

1
2
var s = '';
new RegExp('(choice1|choice2|' + regExpEscape(s) + ')');

这应该可以在JavaScript中很好地编译,但不会以其他一些方式编译。如果打算换口味,应单独检查s === ''的空盒,如:

1
2
var s = '';
new RegExp('(choice1|choice2' + (s ? '|' + regExpEscape(s) : '') + ')');


在jqueryui的autocomplete小部件(1.9.1版)中,它们使用了稍微不同的regex(第6753行),这里是结合@bobine方法的正则表达式。

1
2
3
RegExp.escape = function( value ) {
     return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");
}


Mozilla Developer Network的正则表达式指南提供了这个转义函数:

1
2
3
function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}


没有什么可以阻止您对每个非字母数字字符进行转义:

1
usersString.replace(/(?=\W)/g, '\');

在执行re.toString()时,您会失去一定程度的可读性,但您会赢得大量的简单性(和安全性)。

根据ECMA-262,一方面,正则表达式"语法字符"总是非字母数字的,这样结果是安全的,特殊转义序列(\d\w
总是字母数字的,这样就不会产生错误的控制转义。


在https://github.com/benjamingr/rexexp.escape/上有一个关于regexp.escape的ES7提案,在https://github.com/ljharb/regexp.escape上有一个polyfill。


这是一个较短的版本。

1
2
3
RegExp.escape = function(s) {
    return s.replace(/[$-\/?[-^{|}]/g, '\\$&');
}

这包括%&',的非元字符,但javascript regexp规范允许这样做。


与其只转义在正则表达式中会引起问题的字符(例如黑名单),不如考虑使用白名单。这样,除非每个字符匹配,否则都被视为污点。

对于本例,假设使用以下表达式:

1
RegExp.escape('be || ! be');

此白名单列出了字母、数字和空格:

1
2
3
RegExp.escape = function (string) {
    return string.replace(/([^\w\d\s])/gi, '\\$1');
}

返回:

1
"be \|\| \! be"

这可能会转义不需要转义的字符,但这不会妨碍您的表达式(可能会受到一些轻微的时间惩罚,但为了安全起见,这是值得的)。


xregexp具有一个转义功能:

XRegExp.escape('Escaped? <.>');
// -> 'Escaped\?\ <\.>'

更多信息:http://xregexp.com/api/escape


1
2
3
4
escapeRegExp = function(str) {
  if (str == null) return '';
  return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};


其他答案中的函数对于转义整个正则表达式来说是多余的(它们可能对转义正则表达式的某些部分很有用,这些部分稍后将连接到更大的regexp中)。

如果您退出整个regexp并完成它,则只需引用独立的元字符(.?+*^$|\,或启动某个元字符(([{

1
2
3
String.prototype.regexEscape = function regexEscape() {
  return this.replace(/[.?+*^$|({[\\]/g, '\\$&');
};

是的,让人失望的是,javascript没有这样的内置函数。