提问人:Igor Katson 提问时间:12/30/2008 最后编辑:Mechanical snailIgor Katson 更新时间:6/26/2023 访问量:343413
正则表达式中必须对哪些特殊字符进行转义?
What special characters must be escaped in regular expressions?
问:
我厌倦了总是试图猜测,在使用许多正则表达式实现时,我是否应该转义特殊字符,如''等。()[]{}|
例如,它与 Python、sed、grep、awk、Perl、rename、Apache、find 等不同。 是否有任何规则集可以告诉我何时应该以及何时不应该转义特殊字符?它是否取决于正则表达式类型,如 PCRE、POSIX 或扩展正则表达式?
答:
真的,没有。大约有数以百万计的不同正则表达式语法;它们似乎归结为Perl,EMACS / GNU和AT&T,但我也总是感到惊讶。
不幸的是,实际上没有一组转义码,因为它会根据您使用的语言而有所不同。
但是,保留像正则表达式工具页面或此正则表达式备忘单这样的页面可以大大帮助您快速过滤掉内容。
评论
\<
\>
<
>
\<
\>
不幸的是,像 ( 和 \( 这样的东西的含义在 Emacs 风格的正则表达式和大多数其他样式之间是互换的。因此,如果你试图逃避这些,你可能正在做与你想要的相反的事情。
所以你真的必须知道你想引用什么风格。
POSIX 可识别正则表达式的多种变体 - 基本正则表达式 (BRE) 和扩展正则表达式 (ERE)。即便如此,由于 POSIX 标准化的实用程序的历史实现,也有一些怪癖。
对于何时使用哪种表示法,甚至给定命令使用哪种表示法,没有一个简单的规则。
查看 Jeff Friedl 的 Mastering Regular Expressions 一书。
有时,您列出的字符无法进行简单的转义。例如,使用反斜杠转义括号在 sed 中替换字符串的左侧不起作用,即
sed -e 's/foo\(bar/something_else/'
我倾向于只使用简单的字符类定义,因此上面的表达式变为
sed -e 's/foo[(]bar/something_else/'
我发现这适用于大多数正则表达式实现。
顺便说一句,字符类是非常普通的正则表达式组件,因此它们往往适用于您需要在正则表达式中转义字符的大多数情况下。
编辑:在下面的评论之后,我想我会提到这样一个事实,即在查看正则表达式计算的行为时,您还必须考虑有限状态自动机和非有限状态自动机之间的区别。
您可能想看看“闪亮的球书”,又名 Effective Perl(经过净化的 Amazon 链接),特别是关于正则表达式的章节,以了解正则表达式引擎评估类型的差异。
不是全世界都是PCRE!
无论如何,与 SNOBOL 相比,正则表达式是如此笨拙!这是一门有趣的编程课程!以及 Simula 上的那个。
啊,70年代末在新南威尔士大学学习的乐趣!(-:
评论
哪些字符是你必须的,哪些是你不能逃避的,实际上取决于你正在使用的正则表达式风格。
对于 PCRE 和大多数其他所谓的 Perl 兼容风格,请转义这些外部字符类:
.^$*+?()[{\|
以及这些内部字符类:
^-]\
对于 POSIX 扩展正则表达式 (ERE),请转义以下外部字符类(与 PCRE 相同):
.^$*+?()[{\|
转义任何其他字符是 POSIX ERE 的错误。
在字符类中,反斜杠是 POSIX 正则表达式中的文字字符。你不能用它来逃避任何事情。如果要将字符类元字符作为文字包含在内,则必须使用“巧妙放置”。将 ^ 放在除开头以外的任何位置,将 ] 放在开头,将 - 放在字符类的开头或结尾,以从字面上匹配这些内容,例如:
[]^-]
在 POSIX 基本正则表达式 (BRE) 中,这些是需要转义以隐藏其含义的元字符:
.^$*[\
在 BRE 中转义括号和大括号赋予它们在 ELLE 中未转义版本的特殊含义。一些实现(例如GNU)在转义时也会赋予其他字符特殊的含义,例如\?和 +。转义 .^$*(){} 以外的字符通常是 BRE 的错误。
在字符类中,BRE 遵循与 ER 相同的规则。
如果这一切都让你头晕目眩,请拿起 RegexBuddy 的副本。在“创建”选项卡上,单击“插入令牌”,然后单击“文本”。RegexBuddy 将根据需要添加转义符。
评论
/
不是我提到的任何正则表达式风格的元字符,因此正则表达式语法不需要转义它。当正则表达式在编程语言中被引用为文字时,该语言的字符串或正则表达式格式规则可能需要 或 或 转义,甚至可能要求对“\”进行双重转义。/
"
'
const escapePCRE = string => string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
对于 PHP,“在非字母数字前面加上 ”\“ 来指定它代表自己 http://php.net/manual/en/regexp.reference.escape.php 总是安全的。
除非是 “ 或 '。
要在 PHP 中转义正则表达式模式变量(或部分变量),请使用 preg_quote()
现代正则表达式风格 (PCRE)
包括 C、C++、Delphi、EditPad、Java、JavaScript、Perl、PHP (preg)、PostgreSQL、PowerGREP、PowerShell、Python、REALbasic、Real Studio、Ruby、TCL、VB.Net、VBScript、wxWidgets、XML Schema、Xojo、XRegExp。
PCRE兼容性可能有所不同
无论何处:. ^ $ * + - ? ( ) [ ] { } \ |
传统正则表达式风格 (BRE/ERE)
包括 awk、ed、egrep、emacs、GNUlib、grep、PHP (ereg)、MySQL、Oracle、R、sed.PCRE
支持可以在更高版本中启用或使用扩展
ERE/awk/egrep/emacs
字符类外部: 字符类内部: . ^ $ * + ? ( ) [ { } \ |
^ - [ ]
BRE/ed/grep/sed
在字符类外部: 在字符类内部: 对于文字,不要转义: 对于标准正则表达式行为,转义:
. ^ $ * [ \
^ - [ ]
+ ? ( ) { } |
\+ \? \( \) \{ \} \|
笔记
- 如果不确定某个特定字符,可以像
\xFF
- 字母数字字符不能用反斜杠转义
- 任意符号可以在 PCRE 中使用反斜杠进行转义,但不能对 BRE/ERE 进行转义(它们必须仅在需要时进行转义)。对于 PCRE,只需要在字符类中转义,但为了简单起见,我将它们保存在一个列表中
] -
- 带引号的表达式字符串还必须对周围的引号字符进行转义,并且通常带有双倍的反斜杠(如 JavaScript 中的 vs)
"(\")(/)(\\.)"
/(")(\/)(\.)/
- 除了转义之外,不同的正则表达式实现可能支持不同的修饰符、字符类、锚点、量词和其他功能。有关更多详细信息,请查看 regular-expressions.info,或使用 regex101.com 实时测试您的表达式
评论
-
]
https://perldoc.perl.org/perlre.html#Quoting-metacharacters 和 https://perldoc.perl.org/functions/quotemeta.html
在官方文档中,此类字符称为元字符。引用示例:
my $regex = quotemeta($string);
s/$regex/something/
要知道何时以及什么在不尝试的情况下逃脱是必要的,以准确理解字符串传递的上下文链。您将指定从最远端到最终目的地的字符串,即正则表达式解析代码处理的内存。
注意内存中的字符串是如何处理的:if 可以是代码内部的纯字符串,也可以是输入到命令行的字符串,但 可以是交互式命令行,也可以是 shell 脚本文件中声明的命令行,也可以是代码提到的内存中的变量,或者通过进一步计算的 (string)参数, 或者包含使用任何类型的封装动态生成的代码的字符串......
每个上下文都分配了一些具有特殊功能的字符。
当你想在不使用其特殊功能(上下文的本地)的情况下从字面上传递字符时,你必须转义它,用于下一个上下文......这可能需要一些其他转义字符,这些字符可能还需要在前面的上下文中进行转义。 此外,可能还有字符编码之类的东西(最阴险的是 utf-8,因为它看起来像常见字符的 ASCII,但甚至可以由终端根据其设置进行解释,因此它的行为可能会有所不同,然后是 HTML/XML 的编码属性,有必要准确理解该过程。
例如,命令行中以 开头的正则表达式需要传输到一组 exec 系统调用,这些调用作为文件处理的管道连接,每个 exec 系统调用都有一个参数列表,这些参数由(非转义)空格分隔,可能还有 pipes(|) 和重定向 (> N> N>&M), 括号,和 , ...(所有这些都是 *sh 使用的特殊字符,在下一个上下文中可能会干扰正则表达式的字符,但它们是按顺序计算的:在命令行之前。命令行被程序读取为 bash/sh/csh/tcsh/zsh,基本上在双引号或单引号中,转义更简单,但没有必要在命令行中引号字符串,因为大多数情况下,空格必须以反斜杠为前缀,引号是不必要的,留下字符 * 和 ?的扩展功能可用, 但这解析为与引用中的不同上下文。然后,当计算命令行时,在内存中获取的正则表达式(不是在命令行中写入的正则表达式)将接受与源文件中相同的处理。
对于正则表达式,方括号 [ ] 内有字符集上下文,perl 正则表达式可以由大量非 alfa 数字字符引用(例如 m// 或 m:/better/for/path: ...)。perl -npe
*
?
$(())
您有关于其他答案中字符的更多详细信息,这些详细信息非常特定于最终的正则表达式上下文。正如我所指出的,你提到你发现正则表达式在尝试时会转义,这可能是因为不同的上下文具有不同的字符集,这些字符混淆了你对尝试的记忆(通常反斜杠是在这些不同的上下文中用于转义文字字符而不是其功能的字符)。
对于 Ionic (Typescript),您必须使用双斜杠才能使字符脱落。 例如(这是为了匹配一些特殊字符):
"^(?=.*[\\]\\[!¡\'=ªº\\-\\_ç@#$%^&*(),;\\.?\":{}|<>\+\\/])"
注意这个角色。他们必须被双砍。如果不这样做,代码中将出现类型错误。] [ - _ . /
为了避免担心哪个变体和所有定制的特殊性,只需使用这个通用函数,它涵盖了除 (除非它们具有 Unicode 多字节字符的元) 之外的所有变体:regex
regex
BRE
jot -s '' -c - 32 126 |
mawk ' function ___(__,_) { return substr(_="", gsub("[][!-/_\140:-@{-~]","[&]",__), gsub("["(_="\\\\")"^]",_ "&",__))__ } ($++NF = ___($!_))^_'
!"#$%&'()*+,-./0123456789:;<=>?
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
`abcdefghijklmnopqrstuvwxyz{|}~
[!]["][#][$][%][&]['][(][)][*][+][,][-][.][/]
0 1 2 3 4 5 6 7 8 9 [:][;][<][=][>][?]
[@] ABCDEFGHIJKLMNOPQRSTUVWXYZ [[]\\ []]\^ [_]
[`] abcdefghijklmnopqrstuvwxyz [{][|][}][~]
方括号更容易处理,因为没有触发“转义过多”的警告消息的风险,例如:
function ____(_) {
return substr("", gsub("[[:punct:]]","\\\\&",_))_
}
\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/ 0123456789\:\;\<\=\>\?
\@ABCDEFGHIJKLMNOPQRSTUVWXYZ\[\\\]\^\_\`abcdefghijklmnopqrstuvwxyz \{\|\}\~
gawk: cmd. line:1: warning: regexp escape sequence `\!' is not a known regexp operator
gawk: cmd. line:1: warning: regexp escape sequence `\"' is not a known regexp operator
gawk: cmd. line:1: warning: regexp escape sequence `\#' is not a known regexp operator
gawk: cmd. line:1: warning: regexp escape sequence `\%' is not a known regexp operator
gawk: cmd. line:1: warning: regexp escape sequence `\&' is not a known regexp operator
gawk: cmd. line:1: warning: regexp escape sequence `\,' is not a known regexp operator
gawk: cmd. line:1: warning: regexp escape sequence `\:' is not a known regexp operator
gawk: cmd. line:1: warning: regexp escape sequence `\;' is not a known regexp operator
gawk: cmd. line:1: warning: regexp escape sequence `\=' is not a known regexp operator
gawk: cmd. line:1: warning: regexp escape sequence `\@' is not a known regexp operator
gawk: cmd. line:1: warning: regexp escape sequence `\_' is not a known regexp operator
gawk: cmd. line:1: warning: regexp escape sequence `\~' is not a known regexp operator
使用 Raku(以前称为 Perl_6)
有效(反斜杠或引号除下划线外的所有非字母数字字符):
~$ raku -e 'say $/ if "#.*?" ~~ m/ \# \. \* \? /; #works fine'
「#.*?」
根据 Damian Conway 的 pdf/talk “你所知道的关于正则表达式的一切都是错误的”,正则表达式语言有六种风格。Raku 代表了对标准 Perl(5)/PCRE 正则表达式的重大(~15 年)重新设计。
在这 15 年中,Perl_6 / Raku 语言专家决定,即使目前不存在,所有非字母数字字符(下划线除外)都应保留为正则表达式元字符。若要将非字母数字字符(下划线除外)表示为文字,请反斜杠或转义它们。
因此,如果找到与文本字符序列的匹配项,上面的示例将打印 match 变量。如果您不这样做,会发生什么情况:被解释为注释的开头,点被解释为任何字符(包括空格),星号被解释为零或多量词,问号被解释为零或一量词或节俭(即非贪婪)量词修饰符(取决于上下文):$/
#.*?
#
.
*
?
错误:
~$ ~$ raku -e 'say $/ if "#.*?" ~~ m/ # . * ? /; #ERROR!'
===SORRY!===
Regex not terminated.
at -e:1
------> y $/ if "#.*?" ~~ m/ # . * ? /; #ERROR!⏏<EOL>
Regex not terminated.
at -e:1
------> y $/ if "#.*?" ~~ m/ # . * ? /; #ERROR!⏏<EOL>
Couldn't find terminator / (corresponding / was at line 1)
at -e:1
------> y $/ if "#.*?" ~~ m/ # . * ? /; #ERROR!⏏<EOL>
expecting any of:
/
https://docs.raku.org/language/regexes https://raku.org/
评论
escape()