关于正则表达式:正则表达式中必须转义哪些特殊字符?

What special characters must be escaped in regular expressions?

本问题已经有最佳答案,请猛点这里访问。

在使用许多regexp实现时,我已经厌倦了总是试图猜测是否应该避开诸如'()[]{}|'等特殊字符。

它与诸如python、sed、grep、awk、perl、rename、apache、find等不同。有没有规则集可以告诉我什么时候应该转义特殊字符,什么时候不应该转义特殊字符?它是否依赖于regexp类型,如pcre、posix或扩展regexps?


你必须使用哪些字符,哪些字符不能转义,这取决于你所使用的regex风格。

对于PCRE和大多数其他所谓的Perl兼容风格,请转义这些外部字符类:

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

这些内部字符类:

1
^-]\

对于POSIX扩展regex(ere),转义这些外部字符类(与pcre相同):

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

转义任何其他字符都是posix-ere的错误。

在字符类中,反斜杠是POSIX正则表达式中的一个文本字符。你不能用它来逃避任何事情。如果要将字符类元字符包含为文本,则必须使用"巧妙放置"。将^放在字符类的开头、开头]和开头或结尾以外的任何位置,以逐字匹配这些字符,例如:

1
[]^-]

在POSIX基本正则表达式(BRE)中,这些元字符需要转义以抑制其含义:

1
.^$*

BRES中的转义圆括号和花括号赋予了它们在ERES中的特殊含义。有些实现(例如GNU)在转义时也给其他字符赋予了特殊的含义,例如?+。转义除^$*()以外的字符通常是BRES的错误。

在字符类中,bres遵循与eres相同的规则。

如果所有这些都让你头昏眼花,那就拿一份雷格斯巴迪的副本。在"创建"选项卡上,单击"插入标记",然后单击"文字"。RegexBuddy将根据需要添加转义。


现代Regex香精(PCRE)

包括C、C++、Delphi、EdjPad、Java、JavaScript、Perl、PHP(PREG)、PostgreSQL、PowerGREP、PerfS壳、Python、REALbasic、RealStudio、Ruby、TCL、VB.NET、VBScript、WXWIDGET、XML Schema、XOJO、XRegExp。

&任何地方:. ^ $ * + - ? ( ) [ ] { } \ |


传统Regex口味(bre/ere)

包括awk、ed、egrep、emacs、gnulib、grep、php(ereg)、mysql、oracle、r、sed。
PCRE支持可以在更高版本中启用,也可以使用扩展

ere/awk/egup/emacs

&字符类外部:. ^ $ * + ? ( ) [ { } \ |
&字符类内:^ - [ ]

BRE/ED/GREP/SED

&字符类外部:. ^ $ * [ \
&字符类内:^ - [ ]
&对于文字,不要转义:+ ? ( ) { } |
&对于标准regex行为,escape:\+ \? \( \) \{ \} \|


笔记

  • 如果不确定具体的字符,可以像\xFF那样进行转义。
  • 字母数字字符不能用反斜杠转义
  • 任意符号可以在PCRE中用反斜杠转义,但不能用bre/ere转义(只有在需要时才能转义)。对于pcre ] -,只需要在字符类中进行转义,但为了简单起见,我将它们保存在一个列表中。
  • 带引号的表达式字符串还必须对周围的引号字符进行转义,并且通常使用反斜杠向上翻倍(例如,在javascript中,"(\")(/)(\\.)"/(")(\/)(\.)/)。
  • 除了转义,不同的regex实现可能支持不同的修饰符、字符类、锚、量词和其他特性。有关详细信息,请查看regular-expressions.info,或者使用regex101.com实时测试表达式。


不幸的是,实际上没有一组转义码,因为它根据您使用的语言而变化。

但是,保留一个像正则表达式工具页或这个正则表达式备忘页这样的页面可以帮助您快速筛选出内容。


POSIX可以识别正则表达式的多种变体——基本正则表达式(BRE)和扩展正则表达式(ERE)。即便如此,由于POSIX标准化的实用程序的历史实现,仍然存在一些怪癖。

对于何时使用哪个符号,甚至给定命令使用哪个符号,没有一个简单的规则。

查看Jeff Friedl的《掌握正则表达式》一书。


有时,对于您列出的字符,简单的转义是不可能的。例如,在sed中,使用反斜杠来转义括号在替换字符串的左侧不起作用,即

1
sed -e 's/foo\(bar/something_else/'

我倾向于使用一个简单的字符类定义,因此上面的表达式变成

1
sed -e 's/foo[(]bar/something_else/'

我发现它适用于大多数regexp实现。

btw字符类是非常普通的regexp组件,因此它们在大多数情况下都可以工作,在regexp中需要转义字符。

编辑:在下面的评论之后,我想我会提到一个事实,即在查看regexp评估的行为时,您还必须考虑有限状态自动机和非有限状态自动机之间的区别。

您可能想看一下"闪亮的球书",也就是有效的Perl(经过消毒的Amazon链接),特别是关于正则表达式的章节,了解一下regexp引擎评估类型的差异。

不是所有人都是PCRE!

不管怎么说,和史努博相比,雷格exp实在是太笨重了!现在这是一门有趣的编程课程!以及Simula上的一个。

啊,70年代末在新南威尔士大学学习的乐趣!(-)


不幸的是,诸如(和)之类的内容的含义在Emacs样式的正则表达式和大多数其他样式之间交换。所以,如果你试图逃避这些,你可能会做与你想做的相反的事情。

所以你必须知道你要引用的是什么风格。


实际上,没有。大约有五千多种不同的regex语法;它们似乎归结为perl、emacs/gnu和a t&;t一般来说,但我也总是感到惊讶。


对于php,"在非字母数字前面加上""以指定它代表自身是安全的。"-http://php.net/manual/en/regexp.reference.escape.php。

除非是"或"。:

要在PHP中转义regex模式变量(或部分变量),请使用preg_quote()。


为了准确理解字符串所传递的上下文链,需要知道在不进行尝试的情况下何时以及如何进行转义。您将指定从最远端到最终目的地的字符串,即regexp解析代码处理的内存。

请注意如何处理内存中的字符串:if可以是代码中的普通字符串,也可以是输入到命令行的字符串,但a可以是交互式命令行或shell脚本文件中声明的命令行,也可以是代码中提到的内存中的变量,或者是通过进一步计算得到的(字符串)参数,或者是strin包含动态生成的代码和任何类型的封装…

每个上下文都分配了一些具有特殊功能的字符。

当你想在不使用特殊功能的情况下(在上下文中)逐字传递字符时,你必须在下一个上下文中转义它…它可能需要一些其他转义字符,这些字符可能还需要在前面的上下文中转义。此外,还有字符编码之类的东西(最阴险的是UTF-8,因为它看起来像普通字符的ASCII,但即使是终端也可能根据其设置进行选择性解释,因此它的行为可能会有所不同,然后是HTML/XML的编码属性,必须正确理解该过程。

例如,命令行中以perl -npe开头的regexp需要传输到作为管道连接文件句柄的一组exec系统调用中,每个exec系统调用都只有一个参数列表,这些参数由(非转义)空格分隔,可能还有管道()和重定向(>n>n>&;m)、括号、交互式扩展of.*?$(())…(所有这些都是*sh使用的特殊字符,可能会干扰下一个上下文中正则表达式的字符,但它们的计算顺序是:在命令行之前。命令行由程序读取为bash/sh/csh/tcsh/zsh,基本上是在双引号或单引号内。转义更简单,但不必在命令行中引用字符串,因为大部分空格必须加上反斜杠前缀,并且不需要引号,这样就可以为字符*保留扩展功能。?,但这与引号中的上下文不同。然后,当计算命令行时,在内存中获得的regexp(不是在命令行中写入的)将接受与源文件中相同的处理。对于regexp,方括号[]内有字符集上下文,Perl正则表达式可以由一大组非alfa数字字符引用(例如m/或m:/better/for/path:)。

您在其他答案中有更多关于字符的详细信息,这些信息非常特定于最终的regexp上下文。正如我提到的,您发现regexp转义有尝试,这可能是因为不同的上下文具有不同的字符集,这会混淆您对尝试的记忆(通常反斜杠是在这些不同的上下文中用于转义文字字符而不是其函数的字符)。


https://perldoc.perl.org/perlre.html引用元字符和https://perldoc.perl.org/functions/quotemeta.html

在官方文件中,引用元字符:

1
2
my $regex = quotemate($string)
s/$regex/something/