我厌倦了总是试图猜测,如果我应该转义特殊字符,如'()[]{}|'等使用regexp的许多实现时。
它与Python、sed、grep、awk、Perl、rename、Apache、find等不同。 有没有什么规则集告诉我什么时候应该转义,什么时候不应该转义特殊字符?它是否依赖于regexp类型,如PCRE、POSIX或扩展的regexp ?
我厌倦了总是试图猜测,如果我应该转义特殊字符,如'()[]{}|'等使用regexp的许多实现时。
它与Python、sed、grep、awk、Perl、rename、Apache、find等不同。 有没有什么规则集告诉我什么时候应该转义,什么时候不应该转义特殊字符?它是否依赖于regexp类型,如PCRE、POSIX或扩展的regexp ?
当前回答
有时候简单的转义对于你所列出的字符是不可能的。例如,在sed中,使用反斜杠来转义括号在替换字符串的左边是行不通的
sed -e 's/foo\(bar/something_else/'
我倾向于只使用一个简单的字符类定义,所以上面的表达式变成
sed -e 's/foo[(]bar/something_else/'
我发现它适用于大多数regexp实现。
顺便说一句,字符类是非常普通的regexp组件,所以它们往往适用于大多数需要在regexp中转义字符的情况。
编辑:在下面的评论之后,我只是想提到一个事实,即在查看regexp求值的行为时,您还必须考虑有限状态自动机和非有限状态自动机之间的区别。
您可能想看看“闪亮的球书”,也就是Effective Perl(经过了亚马逊的清洁链接),特别是关于正则表达式的章节,以了解regexp引擎求值类型的差异。
不是所有的世界都是一个PCRE!
无论如何,regexp与SNOBOL相比太笨拙了!这是一门有趣的编程课程!还有Simula上的那个。
啊,70年代末在新南威尔士大学学习的乐趣!(-):
其他回答
哪些字符必须转义,哪些字符不能转义,实际上取决于您使用的正则表达式类型。
对于PCRE和大多数其他所谓的perl兼容版本,转义这些外部字符类:
.^$*+?()[{\|
这些内部字符类:
^-]\
对于POSIX扩展正则表达式(ERE),转义这些外部字符类(与PCRE相同):
.^$*+?()[{\|
转义任何其他字符是POSIX ERE的错误。
在字符类中,反斜杠是POSIX正则表达式中的一个文字字符。你不能用它来逃避任何事情。如果您希望将字符类元字符作为文字包含,则必须使用“巧妙的放置”。将^放在开头以外的任何地方,将]放在开头,将-放在字符类的开头或结尾,以字面上匹配这些字符,例如:
[]^-]
在POSIX基本正则表达式(BRE)中,您需要转义这些元字符以抑制其含义:
.^$*[\
BREs中的转义括号和花括号赋予了它们在EREs中未转义版本的特殊含义。一些实现(例如GNU)在转义时也会赋予其他字符特殊的含义,例如\?和+。转义除。^$*(){}以外的字符通常是BREs的错误。
在字符类内部,bre遵循与EREs相同的规则。
如果所有这些使您头晕目眩,请获取RegexBuddy的副本。在“创建”选项卡上,单击“插入令牌”,然后单击“文字”。RegexBuddy将根据需要添加转义。
要想准确地理解字符串所经过的上下文链,就必须知道何时以及在不进行尝试的情况下进行转义。您将指定从最远的一端到最终目的地(regexp解析代码处理的内存)的字符串。
注意内存中的字符串是如何处理的:if可以是代码中的普通字符串,也可以是输入到命令行的字符串,但a可以是交互式命令行,也可以是shell脚本文件中声明的命令行,也可以是代码中提到的内存中的变量,或者是通过进一步求值的(字符串)参数,或者包含任何类型封装的动态生成的代码的字符串……
每个上下文都赋予了一些具有特殊功能的字符。
When you want to pass the character literally without using its special function (local to the context), than that's the case you have to escape it, for the next context... which might need some other escape characters which might additionally need to be escaped in the preceding context(s). Furthermore there can be things like character encoding (the most insidious is utf-8 because it look like ASCII for common characters, but might be optionally interpreted even by the terminal depending on its settings so it might behave differently, then the encoding attribute of HTML/XML, it's necessary to understand the process precisely right.
E.g. A regexp in the command line starting with perl -npe, needs to be transferred to a set of exec system calls connecting as pipe the file handles, each of this exec system calls just has a list of arguments that were separated by (non escaped)spaces, and possibly pipes(|) and redirection (> N> N>&M), parenthesis, interactive expansion of * and ?, $(()) ... (all this are special characters used by the *sh which might appear to interfere with the character of the regular expression in the next context, but they are evaluated in order: before the command line. The command line is read by a program as bash/sh/csh/tcsh/zsh, essentially inside double quote or single quote the escape is simpler but it is not necessary to quote a string in the command line because mostly the space has to be prefixed with backslash and the quote are not necessary leaving available the expand functionality for characters * and ?, but this parse as different context as within quote. Then when the command line is evaluated the regexp obtained in memory (not as written in the command line) receives the same treatment as it would be in a source file. For regexp there is character-set context within square brackets [ ], perl regular expression can be quoted by a large set of non alfa-numeric characters (E.g. m// or m:/better/for/path: ...).
在其他答案中有关于字符的更多细节,它们非常特定于最终的regexp上下文。正如我注意到的,您提到您发现regexp转义带有尝试,这可能是因为不同的上下文有不同的字符集,这使您对尝试的记忆混淆了(通常在这些不同的上下文中使用反斜杠来转义文字字符,而不是其函数)。
对于Ionic (Typescript),你必须用双斜杠来转义字符。 例如(这是为了匹配一些特殊字符):
"^(?=.*[\\]\\[!¡\'=ªº\\-\\_ç@#$%^&*(),;\\.?\":{}|<>\+\\/])"
注意这个]- _。/字符。它们必须被一分为二。如果不这样做,代码中就会出现类型错误。
POSIX识别正则表达式的多种变体——基本正则表达式(BRE)和扩展正则表达式(ERE)。即使这样,由于POSIX标准化的实用程序的历史实现,也存在一些怪癖。
对于何时使用哪种符号,甚至给定命令使用哪种符号,并没有一个简单的规则。
看看Jeff Friedl的《精通正则表达式》这本书。
为了避免担心哪个regex变量和所有定制的特性,只需使用这个通用函数,它涵盖了除了BRE之外的每个regex变量(除非它们有unicode多字节字符是元字符):
jot -s '' -c - 32 126 |
mawk ' 功能 重返substr(_ =””, gsub ("[][!-/_\ 140 :-@{-~]","[&]",__), gsub ("["(_="\\\\")"^]",_ "&",__))__ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
!"#$%&'()*+,-./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