不同环境下的正则表达式
1 前言
距离初次接触正则表达式已经过了很久了,随着使用环境的增多,才发现,正则表达式不止一种。
当初学习的正则表达式能够在大多数地方使用,但是,偶尔还是会在一些地方碰壁。
经过一番研究后,发现另外两种正则表达式也并没有多么复杂,因此,就在这里总结一下。
2 PCRE
PCER 的全称是 Perl Compatible Regular Expression,即:Perl 兼容的正则表达式。
这应该是目前使用得最广泛的一种正则表达式,我们平时使用的就是这种正则表达式,各种编程语言如 Java、Python、C#、JavaScript 实现的就是这种正则表达式。
在 Python 正则表达式库的官方文档中我们也可以在开头开到这样一句明确的描述:
This module provides regular expression matching operations similar to those found in Perl.
对于这种正则表达式的使用,这里就不做过多的称述了,相关的文档与教程网上很多,也可以参考我以前的博客 正则表达式。
3 POSIX
在 Unix/Linux
环境下,常常会通过命令行进行各种 匹配 操作,常用的两种匹配方式就是通过 Glob 和 正则表达式.
和 Unix/Linux 的文件系统一样,Unix/Linux 环境下的正则表达式也存在一套 POSXI 规范,在这套规范下的正则表达式可以分为 BRE(Basic Regular Expression, 基本型正则表达式) 和 ERE(Extended Regular Express, 扩展型正则表达式) 两种。
这两种正则表达式使用起来感觉没有 PCRE 用起来舒服,同时还容易混淆,但是,由于经常在命令行环境下工作的原因,感觉还是有必要掌握这两种正则表达式。
这两种正则表达式其实并不复杂,只是在部分元字符上具有不同的含义罢了,以下是这些元字符在不同环境下的表现形式:
PCRE | BRE | ERE | 含义 |
---|---|---|---|
( |
\( |
( |
定义子表达式的开始 |
) |
\) |
) |
定义子表达式的结束 |
+ |
\+ |
+ |
匹配前一个字符(子表达式)的一次或多次重复 |
? |
\? |
? |
匹配前一个字符(子表达式)的零次或一次重复 |
\vert |
\\vert |
\vert |
匹配前面的或后面的元素 |
{ |
\{ |
{ |
略 |
} |
\} |
} |
略 |
可以看到,主要的问题就出现在元字符 (
, )
, +
, ?
, |
, {
和 }
上,其中,ERE 的表现形式和 PCRE 是一致的,而 BRE 的表现形式就略显奇怪。
在 BRE 环境下,如果要匹配字符串 abc
一次或多次的话就要写成 \(abc\)\+
, 和我们一般的书写方式 (abc)+
差别不小。
当然,这样做的好处还是有的,比如说需要匹配大量的这几个元字符的使用,用 BRE 就不需要疯狂转义了,比如匹配 (){}+?
, 用 PCRE/ERE
就需要写成 \(\)\{\}\+\?
.
另外,还需要明白的是,在这 BRE 和 ERE 环境中,是不存在诸如 \d
, \s
的特殊元字符的,就算有,那也应该是那个工具提供的额外扩展。
因此,要在 BRE 和 ERE 环境中匹配某类字符,要么使用 字符集合 要么使用 POSIX 字符类:
- 字符集合通过中括号
[]
进行定义,如[1-9]
POSIX 字符类可以参加下表:
字符类 作用 [:alnum:]
任何一个字母或数字 [:alpha:]
任何一个字母 [:blank:]
空格或制表符 [:cntrl:]
ASCII 控制字符(ASCII 0-31, 127) [:digit:]
任何一个数字 [:graph:]
和 [:print:]
一样, 但不包括空格[:lower:]
任何一个小写字母 [:print:]
任何一个可打印字符 [:punct:]
既不属于 [:alnum:]
也不属于[:cntrl:]
的任何一个字符[:space:]
任何一个空白字符, 包括空格 [:upper:]
任何一个大写字符 [:xdigit:]
任何一个十六进制数字
4 原始字符串
这是除了正则表达式的类型以外另一个会影响正则表达式的使用的因素。
对于一般的字符串来说,假如字符串中存在字符 \
, 那么紧跟在字符 \
后面的字符将会被转义。在正则表达式中,我们经常会用到字符 \
本身,因此我们就需要用 \\
来代替 \
.
而在原始字符串环境中,字符串的原始形式和字符串的实际形式是相同的,也就是不会发生转义,这样一来,我们就可以直接将正则表达式写为 \d+
而不是写成 \\d+
.
这我目前接触过的一些编程语言中,像 Python、C#、JavaScript 是支持原始字符串的,同时,还有一种环境也是属于原始字符串的,那就是 命令行 环境。
当我们将命令行参数传递给程序时,传递给程序的参数形式就是字符串的原始形式。
#include <stdio.h> int main(int argc, char* argv[]) { for (int i = 1; i < argc; ++i) { printf("%s\n", argv[i]); } return 0; }
比如说,执行以上的代码可以得到的输出:
$ prog \n \n
5 结语
所以说,我们平时说的正则表达式应该是原始字符串环境下的 PCRE,然后就是在需要转义的字符串环境下 PCRE。
再然后就是一些 古老 的工具使用的 BRE 和 ERE 了,比如 sed、awk、emacs……
啊,为什么先诞生的正则表达式不是 PCRE……