我厌倦了总是试图猜测,如果我应该转义特殊字符,如'()[]{}|'等使用regexp的许多实现时。
()[]{}|
它不同于,例如Python, sed, grep, awk, Perl, rename, Apache, find等。 有没有什么规则集告诉我什么时候应该转义,什么时候不应该转义特殊字符?它是否依赖于regexp类型,如PCRE、POSIX或扩展的regexp ?< / p >
真的,没有。正则表达式语法大约有无数种;它们似乎可以归结为Perl、EMACS/GNU和at&t,但我也总是感到惊讶。
不幸的是,确实没有一组转义码,因为它根据您使用的语言而变化。
然而,保留像正则表达式工具页面或这个正则表达式备忘单这样的页面可以帮助你快速过滤掉内容。
不幸的是,(和\(之类的东西的含义在Emacs样式的正则表达式和大多数其他样式之间交换。因此,如果你试图逃避这些,你可能会做与你想要的相反的事情。
所以你必须知道你想引用的是什么风格。
POSIX识别正则表达式的多种变体——基本正则表达式(BRE)和扩展正则表达式(ERE)。即使这样,由于POSIX标准化的实用程序的历史实现,也存在一些怪癖。
对于何时使用哪种符号,甚至给定命令使用哪种符号,并没有一个简单的规则。
看看杰夫·弗里德的掌握正则表达式书。
有时候简单的转义对于你所列出的字符是不可能的。例如,在sed中,使用反斜杠来转义括号在替换字符串的左边是行不通的
sed -e 's/foo\(bar/something_else/'
我倾向于只使用一个简单的字符类定义,所以上面的表达式变成
sed -e 's/foo[(]bar/something_else/'
我发现它适用于大多数regexp实现。
顺便说一句,字符类是非常普通的regexp组件,所以它们往往适用于大多数需要在regexp中转义字符的情况。
在下面的评论之后,我只是想提到一个事实,即在查看regexp求值的行为时,你还必须考虑有限状态自动机和非有限状态自动机之间的区别。
你可能会想看看“闪亮的球书”,也就是Effective Perl (净化亚马逊链接),特别是关于正则表达式的章节,以了解regexp引擎求值类型的差异。
不是所有的世界都是一个PCRE!
不管怎样,与SNOBOL相比,regexp是如此笨拙!现在那是一门有趣的编程课程!和Simula上的一起。
啊,70年代末在新南威尔士大学学习的乐趣!(-):
哪些字符必须转义,哪些字符不能转义,实际上取决于您使用的正则表达式类型。
对于PCRE和大多数其他所谓的perl兼容版本,转义这些外部字符类:
.^$*+?()[{\|
这些内部字符类:
^-]\
对于POSIX扩展正则表达式(ERE),转义这些外部字符类(与PCRE相同):
转义任何其他字符是POSIX ERE的错误。
在字符类中,反斜杠是POSIX正则表达式中的一个文字字符。你不能用它来逃避任何事情。如果您希望将字符类元字符作为文字包含,则必须使用“巧妙的放置”。将^放在开头以外的任何地方,将]放在开头,将-放在字符类的开头或结尾,以字面上匹配这些字符,例如:
[]^-]
在POSIX基本正则表达式(BRE)中,您需要转义这些元字符以抑制其含义:
.^$*[\
BREs中的转义括号和花括号赋予了它们在EREs中未转义版本的特殊含义。一些实现(例如GNU)在转义时也会赋予其他字符特殊的含义,例如\?和+。转义除。^$*(){}以外的字符通常是BREs的错误。
在字符类内部,bre遵循与EREs相同的规则。
如果所有这些都让你头晕目眩,那就找一个RegexBuddy的拷贝。在“创建”选项卡上,单击“插入令牌”,然后单击“文字”。RegexBuddy将根据需要添加转义。
对于PHP,“在非字母数字前面加上“\”以指定它代表自身总是安全的。”——http://php.net/manual/en/regexp.reference.escape.php。
除非是"或者'。: /
要转义PHP中的正则模式变量(或部分变量),请使用preg_quote()
包括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兼容性可能不同
在任何地方:. ^ $ * + - ? ( ) [ ] { } \ |
. ^ $ * + - ? ( ) [ ] { } \ |
包括awk, ed, egrep, emacs, GNUlib, grep, PHP (ereg), MySQL, Oracle, R, sed。PCRE支持可以在后续版本或通过扩展启用
在awk / egrep / emacs
在字符类之外:. ^ $ * + ? ( ) [ { } \ | 在字符类中:^ - [ ]
. ^ $ * + ? ( ) [ { } \ |
^ - [ ]
BRE / ed / grep和sed
在字符类之外:. ^ $ * [ \ 在字符类中:^ - [ ] 对于字面量,不要转义:+ ? ( ) { } | 对于标准的正则表达式行为,转义:\+ \? \( \) \{ \} \|
. ^ $ * [ \
+ ? ( ) { } |
\+ \? \( \) \{ \} \|
\xFF
] -
"(\")(/)(\\.)"
/(")(\/)(\.)/
https://perldoc.perl.org/perlre.html#Quoting-metacharacters和https://perldoc.perl.org/functions/quotemeta.html
在官方文档中,这样的字符称为元字符。引用的例子:
my $regex = quotemeta($string) s/$regex/something/
要想准确地理解字符串所经过的上下文链,就必须知道何时以及在不进行尝试的情况下进行转义。您将指定从最远的一端到最终目的地(regexp解析代码处理的内存)的字符串。
注意内存中的字符串是如何处理的:if可以是代码中的普通字符串,也可以是输入到命令行的字符串,但a可以是交互式命令行,也可以是shell脚本文件中声明的命令行,也可以是代码中提到的内存中的变量,或者是通过进一步求值的(字符串)参数,或者包含任何类型封装的动态生成的代码的字符串……
每个上下文都赋予了一些具有特殊功能的字符。
当你想字面上传递字符而不使用它的特殊函数(局部上下文),那么你必须转义它,为下一个上下文…这可能需要一些其他转义字符,这些字符可能需要在前面的上下文中进行转义。 此外,还有像字符编码(最隐蔽的是utf-8,因为它看起来像普通字符的ASCII,但甚至可能由终端根据其设置选择性地解释,因此它可能有不同的行为,然后是HTML/XML的编码属性,有必要准确地理解这个过程 < p >。命令行中以perl -npe开头的regexp,需要被传输到一组执行系统调用,以管道连接文件句柄,每个exec系统调用都有一个参数列表,由(非转义的)空格分隔,可能还有管道(|)和重定向(> N> N>&M),括号,*和?的交互扩展,$(())…(所有这些都是*sh使用的特殊字符,在下一个上下文中可能会干扰正则表达式的字符,但它们的求值顺序是:在命令行之前。命令行被程序读取为bash/sh/csh/tcsh/zsh,本质上是在双引号或单引号内,转义更简单,但没有必要在命令行中引用字符串,因为大多数空格必须以反斜杠作为前缀,并且没有必要为字符*和?留下扩展功能,但这将解析为不同的上下文,因为在引号内。然后,当计算命令行时,在内存中获得的regexp(与在命令行中写入的regexp不同)将获得与在源文件中相同的处理。 对于regexp,方括号[]内包含字符集上下文,perl正则表达式可以由一组非字母数字字符引用(例如m//或m:/better/ For /path:…)
perl -npe
*
?
$(())
在其他答案中有关于字符的更多细节,它们非常特定于最终的regexp上下文。正如我注意到的,您提到您发现regexp转义带有尝试,这可能是因为不同的上下文有不同的字符集,这使您对尝试的记忆混淆了(通常在这些不同的上下文中使用反斜杠来转义文字字符,而不是其函数)。
"^(?=.*[\\]\\[!¡\'=ªº\\-\\_ç@#$%^&*(),;\\.?\":{}|<>\+\\/])"
注意这个] [ - _ . /字符。它们必须被一分为二。如果不这样做,代码中就会出现类型错误。
] [ - _ . /
对于awk,如果你是偏执狂,想要逃避一切以防万一,那么这应该可以做到:
awk
从ASCII终端安全列表:
ASCII
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ [\]^_`abcdefghijklmnopqrstuvwxyz{|}~
应用这个:
gsub(/[!-/{-~:-@[-\140]/, "[&]") gsub(/\^|\\/, "\\\\&" )
使:
[!]["][#][$][%][&]['][(][)][*][+][,][-][.][/] 0123456789[:][;][<][=][>][?] [@]ABCDEFGHIJKLMNOPQRSTUVWXYZ[[][\\][]][\^][_] [`]abcdefghijklmnopqrstuvwxyz[{][|][}][~]