正则表达式
正则,就是用字符来描述字符。正则的规则在不同编程语言(C++/Java/Python/Go/Shell)中是通用。
【第一部分】正则表达式里用的字符(可以分为两类)
1 通用编程语言支持的字符
普通字符(包括空格)和 通用编程语言,比如C语言的转义字符(包括制表符、换行符、换页符等)。转义字符,需要用转义符号\
加一个字符来表示一个新的含义,即用两个字符表示一个字符。遇到转义符号,即进入了转义,但如果接下来的字符无法与转义符号构成转义,那么,转义符号被忽略(其实是没有生效或者至少是没法打印出来,转义符号本身还在字符串中,并非不占据字符串空间),接下来的字符表达其原意。转义符号本身为\\
。
2 正则占据的字符
- 用于表示匹配的规则或字符,被正则占用,想表示原字符反而要加转义符。又因为编程语言存在转义,所以,正则想要的转义符本身需要转义,即
\\
。而正则占据以用来表示匹配规则的字符,并非使用频率很高的字符,所以,表达单字符原意反而需要转义的麻烦,也是可以接受的。
a. 表示字符重复数:* +
{n, m}
?
。
b. 表示字符集:[]
c. 表示子正则表达式:()
d. 表示行首尾位置:^
$
。由于正则表达式是按行匹配文本的,所以,这两个符号在正则表达式中也仅能出现一次,且仅出现在正则表达式两端,表示从头开始匹配,或者匹配到结尾,而非这一行中间的某个子字符串匹配即可。因此,正则表达式中间出现的^
字符,可以被正则表达式用来表示非匹配(或者是反向匹配)了,参考21.f(确切的说,是字符集的开始处)。出现了一个字符可以表示两个含义,而其原意需要转义的情况。这样的情况,还有?
也被用来表示非捕获,见【第二部分】(同样是表示规则的符号开始的地方,这样,它出现在正则表达式其他地方的时候就可以不用转义了)。
e. 表示或关系:|
f. 表示任意一个非换行字符:.
(即[^\n\r]
) - 正则表达式的转义字符,与正则表达式中表达被正则占用的单字符原意而需要加
\\
转义类似地,为了进入正则表达式的转义,需要用\\
。但是,例外情况是,
a. 表示某一类符号:\w
(包括字母、数字\d
与下划线_
)\d
\s
(空格、制表符、换行符)
b. 表示(非)某一类字符的边界:\b
\B
- 有些正则表达式标准中,会用
[[::Alpha:]]
这样的规则,这个例子是自解释的。
【第二部分】捕获子字符串、非捕获
注意
在通用编程语言中,由于需要用字符串表示正则表达式,而通用编程语言的字符串存在转义,所以,正则需要的转义符号需要用\\
表示,而转义符号(即反斜线)本身则需要用\\\\
来表示了。但就正则本身来说,如果有办法或者不需要表达通用编程语言中的转义字符的含义,就可以免掉转义转义符号的麻烦。接下来,仅就正则表达式本身来说。
1 捕获
子表达式()
用于捕获子字符串。捕获发生后,在正则表达式中,用\
加数字表示被匹配到的子字符串;而在正则匹配完成后,用$
加数字表示被匹配到的子字符串。在IDE里做全文正则匹配与替换的时候,它很有好用。
2 非捕获(匹配或非匹配预查)
在子正则表达()
里的第一个字符出现?
的时候,做子匹配或者预查(非匹配)
(?:exp)
:不捕获,但是要匹配。例如,fl(?:y|ies)
匹配英语里单复数苍蝇的单词。- 不捕获,也不匹配
a.exp1(?=exp2)
: 正向肯定预查(后面是exp2
吧?)
b.exp1(?!exp2)
: 正向否定预查(后面不是exp2
吧?)
c.(?<=exp2)exp1
: 反向肯定预查(前面是exp2
吧?)
d.(?<!exp2)exp1
: 反向否定预查(前面不是exp2
)
【第三部分】Posix-Char-Classes
(完)