提问人:Lance 提问时间:8/25/2010 最后编辑:Peter MortensenLance 更新时间:11/16/2023 访问量:192758
JavaScript 中是否有 RegExp.escape 函数?
Is there a RegExp.escape function in JavaScript?
问:
我只想从任何可能的字符串中创建一个正则表达式。
var usersString = "Hello?!*`~World()[]";
var expression = new RegExp(RegExp.escape(usersString))
var matches = "Hello".match(expression);
有没有内置的方法?如果不是,人们使用什么?Ruby 具有 RegExp.escape
。我不觉得我需要自己写,必须有一些标准的东西。
答:
另一个答案中链接的功能是不够的。它无法转义 或 (字符串的开头和结尾),或者 ,在字符组中用于范围。^
$
-
使用此功能:
function escapeRegex(string) {
return string.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');
}
虽然乍一看似乎没有必要,但转义(以及 )使该函数适合于将要插入到字符类以及正则表达式主体中的转义字符。-
^
转义使该函数适用于转义字符,以便在 JavaScript 正则表达式文本中使用,以便以后计算。/
由于逃避它们中的任何一个都没有缺点,因此逃避以涵盖更广泛的用例是有意义的。
是的,这是一个令人失望的失败,因为这不是标准 JavaScript 的一部分。
评论
/
quotemeta
\Q
re.escape
preg_quote
Regexp.quote
var e = /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g;
return s.replace(e, '\\$&');
在jQuery UI的自动完成小部件(版本1.9.1)中,他们使用略有不同的正则表达式(第6753行),这是正则表达式与bobince方法的结合。
RegExp.escape = function( value ) {
return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
}
评论
,
#
$.ui.autocomplete.escapeRegex(myString)
这是一个较短的版本。
RegExp.escape = function(s) {
return s.replace(/[$-\/?[-^{|}]/g, '\\$&');
}
这包括 、 、 和 的非元字符,但 JavaScript RegExp 规范允许这样做。%
&
'
,
评论
.
()
[-^
Mozilla Developer Network 的正则表达式指南提供了以下转义函数:
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
}
其他答案中的函数对于转义整个正则表达式来说是大材小用的(它们对于转义正则表达式的一部分可能很有用,这些正则表达式稍后将连接成更大的正则表达式)。
如果你转义了一个完整的正则表达式并完成了它,那么你只需要引用独立的元字符(、、、、)、或开始一些东西(、、)。.
?
+
*
^
$
|
\
(
[
{
String.prototype.regexEscape = function regexEscape() {
return this.replace(/[.?+*^$|({[\\]/g, '\\$&');
};
是的,令人失望的是,JavaScript 没有内置这样的功能。
评论
(text)next
(?:
)
(?:\(text)next)
re\
re
)
对于使用 Lodash 的任何人,从 v3.0.0 开始,内置了 _.escapeRegExp 函数:
_.escapeRegExp('[lodash](https://lodash.com/)');
// → '\[lodash\]\(https:\/\/lodash\.com\/\)'
而且,如果您不想需要完整的 Lodash 库,您可能只需要该功能!
评论
escapeRegExp
这里的大多数表达式都解决了单个特定用例。
没关系,但我更喜欢“总是有效”的方法。
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 编译错误,而不是静默编译错误。#
,并且不需要在 JavaScript 中转义,但在许多其他风格中可以转义。它们在这里被转义,以防正则表达式稍后被传递给另一个程序。\s
如果您还需要使正则表达式面向未来,以防止 JavaScript 正则表达式引擎功能的潜在添加,我建议使用更偏执的:
function regExpEscapeFuture(literal_string) {
return literal_string.replace(/[^A-Za-z0-9_]/g, '\\$&');
}
此函数对每个字符进行转义,但那些明确保证不会用于将来正则表达式风格的语法的字符除外。
对于真正热衷于卫生的人,请考虑以下边缘情况:
var s = '';
new RegExp('(choice1|choice2|' + regExpEscape(s) + ')');
这在 JavaScript 中应该可以很好地编译,但在其他一些风格中则不行。如果打算传递到另一种风格,则应独立检查 的 null 大小写,如下所示:s === ''
var s = '';
new RegExp('(choice1|choice2' + (s ? '|' + regExpEscape(s) : '') + ')');
评论
/
[...]
在 https://github.com/benjamingr/RexExp.escape/ 有一个 RegExp.escape 的 ES7 提案,在 https://github.com/ljharb/regexp.escape 有一个 polyfill。
评论
escapeRegExp = function(str) {
if (str == null) return '';
return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
};
没有什么可以阻止你转义每个非字母数字字符:
usersString.replace(/(?=\W)/g, '\\');
在这样做时,你会失去一定程度的可读性,但你赢得了大量的简单性(和安全性)。re.toString()
根据 ECMA-262,一方面,正则表达式“语法字符”始终是非字母数字的,因此结果是安全的,并且特殊的转义序列 (, , ) 始终是字母数字的,因此不会产生错误的控制转义。\d
\w
\n
评论
.replace(/[^\w]/g, '\\$&')
new RegExp('🍎'.replace(/(?=\W)/g, '\\'), 'u')
\W
.replace(/\W/g, "\\$&");
XRegExp 有一个转义函数:
XRegExp.escape('Escaped? <.>');
// -> 'Escaped\?\ <\.>'
更多信息:http://xregexp.com/api/#escape
与其只转义会导致正则表达式出现问题的字符(例如:黑名单),不如考虑使用白名单。这样,除非匹配,否则每个字符都被视为有污点。
对于此示例,假设以下表达式:
RegExp.escape('be || ! be');
这会将字母、数字和空格列入白名单:
RegExp.escape = function (string) {
return string.replace(/([^\w\d\s])/gi, '\\$1');
}
返回:
"be \|\| \! be"
这可能会逃脱不需要转义的角色,但这并不妨碍你的表达(也许会有一些轻微的时间惩罚 - 但为了安全起见,这是值得的)。
评论
另一种(更安全)的方法是使用 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}'
请注意,您需要传递标志才能使此方法起作用:u
var expression = new RegExp(escapeRegExp(usersString), 'u');
评论
只有 12 个元角色需要转义,而且永远都会有 被视为文字。
对转义字符串执行什么操作、插入到平衡的正则表达式包装器中或附加这些字符串并不重要。这不重要。
使用此方法执行字符串替换
var escaped_string = oldstring.replace(/[\\^$.|?*+()[{]/g, '\\$&');
评论
]
在 https://github.com/benjamingr/RexExp.escape/ 上有一个 RegExp.escape 的 ES7 提案,在 https://github.com/ljharb/regexp.escape 上有一个 polyfill。
基于被拒绝的 ES 提案的示例包括检查该属性是否已经存在,以防 TC39 撤回其决定。
法典:
if (!Object.prototype.hasOwnProperty.call(RegExp, 'escape')) {
RegExp.escape = function(string) {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions#Escaping
// https://github.com/benjamingr/RegExp.escape/issues/37
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
};
}
代码缩小:
Object.prototype.hasOwnProperty.call(RegExp,"escape")||(RegExp.escape=function(e){return e.replace(/[.*+\-?^${}()|[\]\\]/g,"\\$&")});
// ...
var assert = require('assert');
var str = 'hello. how are you?';
var regex = new RegExp(RegExp.escape(str), 'g');
assert.equal(String(regex), '/hello\. how are you\?/g');
还有一个模块:https://www.npmjs.com/package/regexp.escapenpm
可以安装它并按如下方式使用它:
npm install regexp.escape
或
yarn add regexp.escape
var escape = require('regexp.escape');
var assert = require('assert');
var str = 'hello. how are you?';
var regex = new RegExp(escape(str), 'g');
assert.equal(String(regex), '/hello\. how are you\?/g');
在 GitHub & & NPM 页面中,还描述了如何使用此选项的 shim/polyfill。该逻辑基于 ,其中实现包含上面使用的正则表达式。return RegExp.escape || implementation;
NPM 模块是一个额外的依赖项,但它也使外部贡献者更容易识别添加到代码中的逻辑部分。̄\(ツ)/¯
评论
我借用了上面 bobince 的答案,并创建了一个标记模板函数,用于创建一个 其中部分值被转义,部分不被转义。RegExp
正则表达式转义.js
RegExp.escape = text => text.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
RegExp.escaped = flags =>
function (regexStrings, ...escaped) {
const source = regexStrings
.map((s, i) =>
// escaped[i] will be undefined for the last value of s
escaped[i] === undefined
? s
: s + RegExp.escape(escaped[i].toString())
)
.join('');
return new RegExp(source, flags);
};
function capitalizeFirstUserInputCaseInsensitiveMatch(text, userInput) {
const [, before, match, after ] =
RegExp.escaped('i')`^((?:(?!${userInput}).)*)(${userInput})?(.*)$`.exec(text);
return `${before}${match.toUpperCase()}${after}`;
}
const text = 'hello (world)';
const userInput = 'lo (wor';
console.log(capitalizeFirstUserInputCaseInsensitiveMatch(text, userInput));
对于我们的 TypeScript 粉丝...
global.d.ts(全球.d.ts)
interface RegExpConstructor {
/** Escapes a string so that it can be used as a literal within a `RegExp`. */
escape(text: string): string;
/**
* Returns a tagged template function that creates `RegExp` with its template values escaped.
*
* This can be useful when using a `RegExp` to search with user input.
*
* @param flags The flags to apply to the `RegExp`.
*
* @example
*
* function capitalizeFirstUserInputCaseInsensitiveMatch(text: string, userInput: string) {
* const [, before, match, after ] =
* RegExp.escaped('i')`^((?:(?!${userInput}).)*)(${userInput})?(.*)$`.exec(text);
*
* return `${before}${match.toUpperCase()}${after}`;
* }
*/
escaped(flags?: string): (regexStrings: TemplateStringsArray, ...escapedVals: Array<string | number>) => RegExp;
}
评论
这是永久的解决方案。
function regExpEscapeFuture(literal_string) {
return literal_string.replace(/[^A-Za-z0-9_]/g, '\\$&');
}
刚刚发布了一个基于 RegExp.escape 填充码的正则表达式转义要点,而该填充码又基于被拒绝的 RegExp.escape 提案。看起来与公认的答案大致相同,只是它没有转义字符,根据我的手动测试,这似乎实际上没问题。-
撰写本文时的当前要点:
const syntaxChars = /[\^$\\.*+?()[\]{}|]/g
/**
* Escapes all special special regex characters in a given string
* so that it can be passed to `new RegExp(escaped, ...)` to match all given
* characters literally.
*
* inspired by https://github.com/es-shims/regexp.escape/blob/master/implementation.js
*
* @param {string} s
*/
export function escape(s) {
return s.replace(syntaxChars, '\\$&')
}
这是一个非基于正则表达式的 replaceAll 版本,其运行速度比类似的基于正则表达式的版本快 40%。
使用 string.includes 函数和三元添加转义反斜杠而不是正则表达式。
const escapeRegex = s => s.replaceAll("", a => "\\/-^$*+?.|()[]{}".includes(a) ? "\\" + a : a)
评论
RegExp.escape
目前正在开发中,非常欢迎任何认为他们有宝贵意见的人做出贡献。Core-JS 和其他 polyfills 提供了它。