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

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

有内置的方法吗?如果不是,人们用什么?Ruby有RegExp.escape。我觉得我不需要写我自己的,必须有一些标准的东西。


当前回答

刚刚发布了一个基于RegExp.escape shim的regex转义要点,而RegExp.escape shim又是基于被拒绝的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, '\\$&')
}

其他回答

这是长久之计。

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

在另一个答案中链接的函数是不够的。它不能转义^或$(字符串的开始和结束),或-,在字符组中用于范围。

使用这个函数:

function escapeRegex(string) {
    return string.replace(/[/\-\\^$*+?.()|[\]{}]/g, '\\$&');
}

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

转义/使函数适合转义在JavaScript正则表达式文字中使用的字符,以供以后计算。

由于转义它们都没有任何缺点,因此转义以覆盖更广泛的用例是有意义的。

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

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

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

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正则表达式引擎中执行。

涉及的特殊字符:

-: Creates a character range in a character class. [ / ]: Starts / ends a character class. { / }: Starts / ends a numeration specifier. ( / ): Starts / ends a group. * / + / ?: Specifies repetition type. .: Matches any character. \: Escapes characters, and starts entities. ^: Specifies start of matching zone, and negates matching in a character class. $: Specifies end of matching zone. |: Specifies alternation. #: Specifies comment in free spacing mode. \s: Ignored in free spacing mode. ,: Separates values in numeration specifier. /: Starts or ends expression. :: Completes special group types, and part of Perl-style character classes. !: Negates zero-width group. < / =: Part of zero-width group specifications.

注:

/在任何类型的正则表达式中都不是严格必要的。但是,如果有人(不寒而栗)执行eval("/" + pattern + "/"); ,确保如果字符串在数值说明符中是整数,它将正确地导致RegExp编译错误,而不是无声地编译错误。 #,和\s在JavaScript中不需要转义,但在许多其他风格中需要转义。它们在这里转义,以防稍后将正则表达式传递给另一个程序。


如果你还需要对JavaScript正则表达式引擎的潜在功能进行未来验证,我建议使用更偏执狂的方法:

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

该函数转义所有字符,除了那些明确保证不会在将来的正则表达式中用于语法的字符。


对于真正热衷于卫生的人来说,考虑一下这个边缘情况:

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

这在JavaScript中应该编译得很好,但在其他类型中就不行。如果打算传递给另一个flavor,则应该单独检查s === "的空大小写,如下所示:

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

过去和将来只有12个元字符需要转义 被认为是字面上的

对转义字符串做什么并不重要,插入到平衡的正则表达式包装器或追加。没关系。

字符串替换使用这个吗

var escaped_string = oldstring.replace(/[\\^$.|?*+()[{]/g, '\\$&');

另一种(更安全的)方法是使用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');