Javascript中是否有RegExp.escape函数?

Lan*_*ard 404 javascript regex

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

var usersString = "Hello?!*`~World()[]";
var expression = new RegExp(RegExp.escape(usersString))
var matches = "Hello".match(expression);
Run Code Online (Sandbox Code Playgroud)

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

bob*_*nce 528

上面链接的功能不足.它无法转义^$(字符串的开头和结尾),或者-在字符组中用于范围.

使用此功能:

RegExp.escape= function(s) {
    return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
};
Run Code Online (Sandbox Code Playgroud)

虽然乍一看似乎没必要,但转义-(以及^)使该函数适合于转义字符插入到字符类以及正则表达式的主体中.

Escaping /使该函数适合转义在JS regex文字中用于以后eval的字符.

因为逃避它们中的任何一个都没有任何缺点,所以逃避覆盖更广泛的用例是有意义的.

是的,令人失望的是,这不是标准JavaScript的一部分.

  • @Paul:Perl`jotemeta`(`\ Q`),Python`re.escape`,PHP`preg_quote`,Ruby`Regexp.quote` ... (28认同)
  • 实际上,我们根本不需要逃避`/` (15认同)
  • bobince不关心eslint的意见 (14认同)
  • 如果要在循环中使用此函数,最好使RegExp对象成为自己的变量`var e =/[\ - \[\]\/\{\} \(\)\*\+\?\.\\\ ^\$\|]/g;`然后你的函数是`return s.replace(e,'\\ $&');`这样你只需要实例化一次RegExp. (13认同)
  • 反对增强内置对象的标准参数在这里适用,不是吗?如果ECMAScript的未来版本提供的"RegExp.escape"实现与您的实现不同,会发生什么?这个功能不能附加到任何东西不是更好吗? (12认同)
  • 因为正确地嵌套转义很棘手,而且错误的结果非常严重(跨站点脚本漏洞),所以将数据注入 JavaScript 代码通常是一个坏主意。通常最好将内容写入数据属性(例如`<html data-jsstr="{{myStr}}">`,使用把手的普通 HTML 转义),然后从静态 JS 读取该属性的内容。 (5认同)
  • @spinningarrow:它代表整个匹配的字符串,就像许多其他正则表达式系统中的"组0"一样.[DOC](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter) (4认同)
  • `$&`做什么? (3认同)
  • 但是也许您想对字符进行转义以将它们“放在”字符范围内。相对于在环境不佳的情况下逃生并造成问题,IMO更好地进行无害的逃生。FWIW我个人希望在这里明确看到这些字符;我们不打代码高尔夫。 (3认同)
  • 在编辑之前,我相信原始答案是正确的.我很确定没有必要在字符类中转义正斜杠.它似乎没有害处,但不是必需的. (2认同)
  • @Radu:你有一个字符串文字问题, `'a\.b'`===`'ab'` :-) (2认同)
  • BTW要注意调试器控制台:IE,Firefox和Chrome都以伪文字形式"a\.b"显示字符串`a\.b`,这是误导性的,因为它不是该值的有效字符串文字(应该是"一个\\.b"`.感谢不必要的额外混乱,浏览器. (2认同)
  • 你不需要逃避' - '.当你转义'['时,' - '不在字符类中,它没有特殊含义.'/'也不是必需的. (2认同)
  • @Shaggydog:肯定可以,但是我想不出一个地方```在正则表达式语法中是特殊的,所以我不确定它会带来什么好处. (2认同)
  • @Shaggydog:您正在谈论JavaScript字符串文字转义。这与正则表达式转义是另一回事。它们都使用反斜杠,但是规则完全不同。(如果您在正则表达式内的字符串中有一个字符串,那么您将必须使用两种转义类型,一种是另一种。) (2认同)
  • @Redu:???您似乎调用了`RegExp` 构造函数而不是`Regexp.escape`... (2认同)
  • 在“敌对的”通用函数中,您可能希望考虑通过执行`String(s).replace(/ [-\ / \\ ^ $ * + ?.()| [\] {}]来保护自己免受javascript输入的侵害。 / g,'\\ $&');`例如,当您的字符串是数字时,这很有用。 (2认同)
  • 默认情况下,ESLint 使用此正则表达式抛出错误(`no-useless-escape`):不必要的转义字符:\/ (2认同)
  • 表达式可以简化为: `/[$(-+.\/?[-^{|}]/` (节省 5 个字符)。您不需要转义 `-` 因为您已经转义了 `[ ` 和 `]` 意味着不会有字符组。此外,有两个字符序列可以写为范围。一个位于 `(` 和 `+`(40 到 43)之间,另一个位于 `[` 之间和“^”(91 到 94)。 (2认同)
  • @JoãoPimentelFerreira 好吧,引号对正则表达式没有特殊含义(请参阅上面 Shaggydog 的评论)。 (2认同)
  • @JoãoPimentelFerreira,这不是正则表达式逃脱,这是JavaScript字符串文字转义.这些语法的规则是不同的,不兼容; 将regex escaper应用于`myStr`即使引用被转义也不会使结果正确.如果你正在将字符串写入字符串文字中的正则表达式*中,则需要首先对其进行正则表达式转义,然后使用字符串文字转义结果(例如,反斜杠最终为四重反斜杠). (2认同)
  • @JoãoPimentelFerreira 如果您注入的任何数据来自应用程序外部,那么提供数据的任何人都可以导致他们自己选择的代码在使用应用程序输出的任何其他人的浏览器上运行,从而允许他们执行任何用户操作可以在你的网站上做。这就是跨站脚本攻击,它是当今网络上最严重、最普遍的安全问题之一。 (2认同)
  • 令人失望的是,[未来几年以及其他许多改进](https://esdiscuss.org/topic/regexp-escape)...... (2认同)

gus*_*nke 100

对于使用lodash的任何人,从v3.0.0开始,内置了一个_.escapeRegExp函数:

_.escapeRegExp('[lodash](https://lodash.com/)');
// ? '\[lodash\]\(https:\/\/lodash\.com\/\)'
Run Code Online (Sandbox Code Playgroud)

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

  • 甚至还有一个这样的npm包!https://www.npmjs.com/package/lodash.escaperegexp (5认同)
  • @RobEvans我的回答以_"对于任何使用lodash的人"_开头,我甚至提到你只需要*只需要`escapeRegExp`函数. (5认同)
  • 这会导入大量代码,而对于如此简单的事情来说,这些代码实际上并不需要存在。使用 bobince 的答案...对我有用,而且它的加载字节数比 lodash 版本少得多! (2认同)
  • @gustavohenke抱歉,我应该更清楚一些,我在“仅此功能”中包含了链接到的模块,这就是我的评论。如果您看一看,实际上应该是一个带有单个正则表达式的单个函数的代码很多。同意如果您已经在使用lodash,则可以使用它,否则请使用其他答案。抱歉,不清楚的评论。 (2认同)
  • @maddob我看不到你提到的\ x3:我的转义字符串看起来很好,正如我所期待的那样 (2认同)

Pi *_*ion 37

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

没关系,但我更喜欢"永远有效"的方法.

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

这将为正则表达式中的任何以下用法"完全转义"文字字符串:

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

涵盖的特殊字符:

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

笔记:

  • /在任何正则表达式中都不是必需的.但是,如果有人(不寒而栗)这样做,它会受到保护eval("/" + pattern + "/");.
  • , 确保如果字符串在数字说明符中是一个整数,它将正确地导致RegExp编译错误,而不是静默编译错误.
  • #,\s不需要在JavaScript中进行转义,但在许多其他方面都有.如果正则表达式稍后将传递给另一个程序,它们将在此处转义.

如果您还需要针对JavaScript正则表达式引擎功能的潜在添加进行面向未来的正则表达式,我建议使用更偏执的:

function regExpEscapeFuture(literal_string) {
    return literal_string.replace(/[^A-Za-z0-9_]/g, '\\$&');
}
Run Code Online (Sandbox Code Playgroud)

此函数会转义除了明确保证在将来的正则表达式风格中不用于语法的那些字符.


对于真正的卫生敏锐,请考虑这种边缘情况:

var s = '';
new RegExp('(choice1|choice2|' + regExpEscape(s) + ')');
Run Code Online (Sandbox Code Playgroud)

应该在JavaScript中编译良好,但不会在其他一些风格.如果打算传递给另一种味道,s === ''应该独立检查null的情况,如下所示:

var s = '';
new RegExp('(choice1|choice2' + (s ? '|' + regExpEscape(s) : '') + ')');
Run Code Online (Sandbox Code Playgroud)


qui*_*int 24

Mozilla开发者网络的正则表达式指南提供了这种转义功能:

function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
Run Code Online (Sandbox Code Playgroud)


Pie*_* SS 21

在jQueryUI的自动完成小部件(版本1.9.1)中,他们使用略有不同的正则表达式(第6753行),这里是正则表达式与@bobince方法相结合.

RegExp.escape = function( value ) {
     return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您想重用jquery UI的实现而不是在本地粘贴代码,请使用`$ .ui.autocomplete.escapeRegex(myString)`. (18认同)
  • 唯一的区别是它们逃避`,`(这不是元字符),以及`#`和空格只在自由间隔模式下有效(JavaScript不支持).但是,他们确实做对了,不要逃避正斜线. (4认同)
  • lodash也有这个,_.escapeRegExp和https://www.npmjs.com/package/lodash.escaperegexp (2认同)

dal*_*ege 12

什么都不能阻止你逃避每个非字母数字字符:

usersString.replace(/(?=\W)/g, '\\');
Run Code Online (Sandbox Code Playgroud)

在做的时候你会失去一定程度的可读性,re.toString()但你会赢得很多简单(和安全性).

根据ECMA-262,在一方面,正则表达式"的语法的字符"总是非字母数字,使得结果是安全的,和特殊的转义序列(\d,\w,\n)总是字母数字,使得没有假控制逃逸会产生.

  • 这在Unicode模式下失败.例如,`new RegExp(''.replace(/(?=\W)/ g,'\\'),'u')`抛出异常,因为`\ W`分别匹配代理对的每个代码单元,导致无效的转义码. (6认同)
  • 替代:`.replace(/\W/g, "\\$&amp;");` (2认同)

Dre*_*ope 12

https://github.com/benjamingr/RexExp.escape/上有一个关于 RegExp.escape 的 ES7 提案, https://github.com/ljharb/regexp.escape上提供了一个 polyfill 。

\n

基于被拒绝的 ES 提案的示例包括检查该属性是否已存在,以防 TC39 收回其决定。

\n
\n

代码:

\n
if (!Object.prototype.hasOwnProperty.call(RegExp, \'escape\')) {\n  RegExp.escape = function(string) {\n    // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping\n    // https://github.com/benjamingr/RegExp.escape/issues/37\n    return string.replace(/[.*+\\-?^${}()|[\\]\\\\]/g, \'\\\\$&\'); // $& means the whole matched string\n  };\n}\n
Run Code Online (Sandbox Code Playgroud)\n

代码缩小:

\n
Object.prototype.hasOwnProperty.call(RegExp,"escape")||(RegExp.escape=function(e){return e.replace(/[.*+\\-?^${}()|[\\]\\\\]/g,"\\\\$&")});\n
Run Code Online (Sandbox Code Playgroud)\n
\n
// ...\nvar assert = require(\'assert\');\n \nvar str = \'hello. how are you?\';\nvar regex = new RegExp(RegExp.escape(str), \'g\');\nassert.equal(String(regex), \'/hello\\. how are you\\?/g\');\n
Run Code Online (Sandbox Code Playgroud)\n
\n

还有一个npm模块位于:\n https://www.npmjs.com/package/regexp.escape

\n
\n

人们可以安装它并按如下方式使用它:

\n
\n
npm install regexp.escape\n
Run Code Online (Sandbox Code Playgroud)\n

或者

\n
yarn add regexp.escape\n
Run Code Online (Sandbox Code Playgroud)\n
\n
var escape = require(\'regexp.escape\');\nvar assert = require(\'assert\');\n \nvar str = \'hello. how are you?\';\nvar regex = new RegExp(escape(str), \'g\');\nassert.equal(String(regex), \'/hello\\. how are you\\?/g\');\n
Run Code Online (Sandbox Code Playgroud)\n

在 GitHub && NPM 页面中也描述了如何为此选项使用 shim/polyfill。该逻辑基于return RegExp.escape || implementation;,其中实现包含上面使用的正则表达式。

\n
\n

NPM 模块是一个额外的依赖项,但它也使外部贡献者更容易识别添加到代码中的逻辑部分。\xc2\xaf\\ (\xe3\x83\x84) /\xc2\xaf

\n


小智 11

有一个ES7提案RegExp.escape在https://github.com/benjamingr/RexExp.escape/,与可用填充工具https://github.com/ljharb/regexp.escape.

  • 看起来像这样[没有进入ES7](https://github.com/tc39/proposals/blob/master/finished-proposals.md).它看起来像是[拒绝支持寻找模板标签](https://github.com/tc39/proposals/blob/master/inactive-proposals.md). (8认同)

soh*_*pro 8

另一种(更安全)的方法是使用 unicode 转义格式转义所有字符(而不仅仅是我们目前知道的一些特殊字符)\u{code}

function escapeRegExp(text) {
    return Array.from(text)
           .map(char => `\\u{${char.charCodeAt(0).toString(16)}}`)
           .join('');
}

console.log(escapeRegExp('a.b')); // '\u{61}\u{2e}\u{62}'
Run Code Online (Sandbox Code Playgroud)

请注意,您需要传递u标志才能使此方法起作用:

var expression = new RegExp(escapeRegExp(usersString), 'u');
Run Code Online (Sandbox Code Playgroud)


kzh*_*kzh 6

这是一个较短的版本。

RegExp.escape = function(s) {
    return s.replace(/[$-\/?[-^{|}]/g, '\\$&');
}
Run Code Online (Sandbox Code Playgroud)

这包括非元字符%&',和,,但JavaScript的正则表达式规范允许这样做。

  • 由于字符范围隐藏了字符列表,因此我不会使用该“更短”的版本,这使乍一看更难验证正确性。 (2认同)