在放入正则表达式之前应该转义的所有字符列表是什么?

82

请问是否能提供需要转义的特殊字符的完整列表?

我担心自己不知道其中的一些。


12
这个列表令人惊讶地很难找到。 - dwjohnston
7个回答

75

PHP的preg_quote函数接受任意字符串,并“在正则表达式语法中的每个字符前面放置反斜杠”,从而转义这些字符:

. \ + * ? [ ^ ] $ ( ) { } = ! < > | : -

以下是JavaScript preg_quote的简化版本,取自Locutus:

function escapeRegexChars(str) {
  return str.replace(new RegExp('[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\-]', 'g'), '\\$&')
}

3
如果您正在使用 str_replace 转义这些字符,应该先转义反斜杠\ 。在上面的列表中,如果将.替换为\ .,则 . 将被替换为\.,而这不是所需的结果。 - Mark Rose
冒号(即“:”)不应该在这里,因为它在JavaScript中不是一个特殊的正则表达式字符。 - manymanymore
MDN在https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions文章中推荐了另一种表达方式。 - Vladimir Nikotin

9
根据这个网站,需要转义的字符列表如下:
[、反斜杠\、脱字符^、美元符号$、句点或点号.、竖线或管道符号|、问号?、星号或乘号*、加号+、左圆括号(和右圆括号)。
此外,您还需要转义由Javascript解释器解释为字符串结束的字符,即单引号'或双引号"。

不知道如何评价那个网站。它涵盖了许多正则表达式的变体,但没有说明这个列表适用于哪些变体。 - BaldEagle

7

参考Tatu Ulmanen的答案,我的C#解决方案如下:

private static List<string> RegexSpecialCharacters = new List<string>
{
    "\\",
    ".",
    "+",
    "*",
    "?",
    "[",
    "^",
    "]",
    "$",
    "(",
    ")",
    "{",
    "}",
    "=",
    "!",
    "<",
    ">",
    "|",
    ":",
    "-"
};


foreach (var rgxSpecialChar in RegexSpecialCharacters)
                rgxPattern = input.Replace(rgxSpecialChar, "\\" + rgxSpecialChar);

请注意,我已经交换了 '\' 和 '.' 的位置,如果不先处理斜杠,则会导致 '\' 值加倍。 编辑 以下是javascript翻译。
var regexSpecialCharacters = [
    "\\", ".", "+", "*", "?",
    "[", "^", "]", "$", "(",
    ")", "{", "}", "=", "!",
    "<", ">", "|", ":", "-"
];

regexSpecialCharacters.forEach(rgxSpecChar => 
    input = input.replace(new RegExp("\\" + rgxSpecChar,"gm"), "\\" + 
rgxSpecChar))

3
OP不是要求JavaScript吗? - Jamie Hutber
@JamieHutber 他们做了。 - hngr18
解释一下:他们后来编辑了他们的标签。 - Jamie Hutber

5

在一个字符集合内,如果要匹配一个字面上的连字符-,当它不位于开头或结尾时,需要进行转义。例如,在下面的模式中最后一个连字符的位置,需要进行转义:

[a-z0-9\-_]+

但在这里不需要转义:

[a-z0-9_-]+

如果你未能转义连字符,引擎将试图将其解释为前一个字符和下一个字符之间的范围(就像 a-z 匹配 a 和 z 之间的任何字符一样)。
此外,在字符集内部不需要转义 / (尽管在字符集外部需要转义)。因此,以下语法是有效的;
const pattern = /[/]/;

2

随着在JavaScript中引入Unicode正则表达式(即使用u标志构造的正则表达式),这里的答案变得更加复杂。特别是:

  • 非Unicode正则表达式支持“身份”转义;也就是说,如果一个字符在正则表达式模式中没有特殊的解释,那么对它进行转义不会产生任何效果。这意味着/a//\a/将以相同的方式匹配。

  • Unicode正则表达式更加严格——尝试转义一个不被视为“特殊”的字符是错误的。例如,/\a/u不是有效的正则表达式。

可以从ECMAScript标准中推断出一组特殊解释的字符;例如,在ECMAScript 2021中,https://262.ecma-international.org/12.0/#sec-patterns,我们看到以下“语法”字符:

SyntaxCharacter :: one of
    ^ $ \ . * + ? ( ) [ ] { } |

特别是与其他答案相比,注意到!<>:-不被视为语法字符。相反,在特定的上下文中,这些字符可能只有特殊的解释。
例如,只有在用作捕获组名称时,<>字符才具有特殊的解释;例如:
/(?<name>\w+)/

由于在 Unicode 正则表达式中,<> 不被视为语法字符,因此对它们进行转义会导致错误。

> /\</
/\</

> /\</u
Uncaught SyntaxError: Invalid regular expression: /\</: Invalid escape

此外,-字符仅在字符类中被特殊解释,用于表示字符范围,例如。
/[a-z]/

在 Unicode 正则表达式中,将 - 转义置于字符类内是有效的,但放在字符类外则无效。

> /\-/
/\-/

> /\-/u
Uncaught SyntaxError: Invalid regular expression: /\-/: Invalid escape

> /[-]/
/[-]/

> /[\-]/u
/[\-]/u

对于使用/ /语法(而不是new RegExp())构建的正则表达式,内部斜杠(/)需要进行转义,但这是为了避免JavaScript解析器中出现歧义,而不是为了正则表达式本身,以避免模式结束标记/与模式中的字面量/之间的混淆。
> /\//.test("/")
true

> new RegExp("/").test("/")
true

不过,如果你的目标是转义字符,使它们在正则表达式中不被特殊解释,那么只需要转义语法字符就足够了。例如,如果我们想匹配字面字符串(?:hello),我们可以使用以下代码:

> /\(\?:hello\)/.test("(?:hello)")
true

> /\(\?:hello\)/u.test("(?:hello)")
true

请注意,冒号(:)字符不需要转义。在模式(?:hello)中,冒号字符可能看起来需要转义,因为它在该模式中有特殊的解释,但由于它不被视为语法字符,因此不需要转义它。(转义前面的(?字符足以确保冒号不被特别解释。)
以上代码片段已经进行了测试:
$ node -v
v16.14.0

$ node -p process.versions.v8
9.4.146.24-node.20

我很感激你提供了详尽的答案,但如果你能够事先给出一个简短而又最有用的回答/总结,而不是期望每个人都阅读整个答案,那将会更好。 - user3064538

1

问题:

const character = '+'
new RegExp(character, 'gi') // error

智能解决方案:

// with babel-polyfill
// Warning: will be removed from babel-polyfill v7
const character = '+'
const escapeCharacter = RegExp.escape(character)
new RegExp(escapeCharacter, 'gi') // /\+/gi

// ES5
const character = '+'
const escapeCharacter = escapeRegExp(character)
new RegExp(escapeCharacter, 'gi') // /\+/gi

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

0

我在寻找与ESLint的“no-useless-escape”设置相关的列表,用于正则表达式。发现一些提到的字符在JS中不需要转义。这里另一个答案中更长的列表是针对PHP的,它确实需要转义其他字符。

这个ESLint的github问题中,大约在中间位置,用户not-an-aardvark解释了为什么该问题中引用的字符可能需要转义。

在javascript中,需要转义的字符是语法字符或以下字符之一:

^ $ \ . * + ? ( ) [ ] { } |

我链接到的github问题的回复包括有关“附录B”语义(我不太了解)的解释,允许取消转义上述提到的4个字符:) ] { }

另一个需要注意的是,转义不需要转义的字符不会造成任何伤害(除非你试图转义转义字符)。因此,我的个人经验法则是:“当你不确定时,请进行转义”


不幸的是,这个说法已经不再正确了,至少对于 Firefox 中的<input pattern="">来说是这样的:https://dev59.com/oVoU5IYBdhLWcg3w559R - nrkn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接