文章目录
- 一、正则表达式引擎
- 二、正则表达式分类
- 三、正则表达式比较
- 四、Linux/OS X 下常用命令与正则表达式的关系
一、正则表达式引擎
正则引擎大体上可分为不同的两类:DFA
和 NFA
,而 NFA
又基本上可以分为传统型 NFA
和 POSIX NFA
。
-
DFA(Deterministic Finite Automaton)
确定型有穷自动机 -
NFA(Non-deterministic finite automaton)
非确定型有穷自动机
(1) Traditional NFA
(2) POSIX NFA
DFA
引擎因为不需要回溯,所以匹配快速,但不支持捕获组,所以也就不支持反向引用和 $number
这种引用方式,目前使用 DFA
引擎的语言和工具主要有 awk
、egrep
和 lex
。
POSIX NFA
主要指符合 POSIX
标准的 NFA
引擎,它的特点主要是提供 longest-leftmost
匹配,也就是在找到最左侧最长匹配之前,它将继续回溯。同 DFA
一样,非贪婪模式或者说忽略优先量词对于 POSIX NFA
同样是没有意义的。
目前 JavaScript,Java,Php,Python,C# 等语言均实现了 NFA 引擎。
大多数语言和工具使用的是传统型的 NFA
引擎,它有一些 DFA
不支持的特性:
-
捕获组、反向引用和
$number
引用方式; -
环视(Lookaround),
(?<=…)
、(?<!…)
、(?=…)
、(?!…)
,或者有的有文章叫做预搜索; -
忽略优先量词
??
、*?
、+?
、{m,n}?
、{m,}?
,或者有的文章叫做非贪婪模式; -
占有优先量词
?+
、*+
、++
、{m,n}+
、{m,}+
,目前仅Java
和PCRE
支持,固化分组(?>…)
。
按以上的说法,awk、egrep、lex 使用 DFA 引擎,所以不支持捕获组、反向引用和 $number 引用方式;不支持环视;不支持忽略优先修饰符;不支持占有优先修饰符。我觉得有问题,改天再验证吧!!
二、正则表达式分类
在 Linux 和 OS X 下,常见的正则表达式,至少有以下三种:
- 基本的正则表达式(Basic Regular Expression 又叫 Basic RegEx 简称 BREs)
- 扩展的正则表达式(Extended Regular Expression 又叫 Extended RegEx 简称 EREs)
- Perl 的正则表达式(Perl Regular Expression 又叫 Perl RegEx 简称 PREs)
三、正则表达式比较
字符 | 说明 | Basic RegEx | Extended RegEx | Python RegEx | Perl RegEx |
---|---|---|---|---|---|
^ | 匹配行首或者字符串的开始处 | ^ | ^ | ^ | ^ |
$ | 匹配行尾或者字符串的结尾处 | $ | $ | $ | $ |
^$ | 匹配空行 | ^$ | ^$ | ^$ | ^$ |
\< | 匹配单词开始处。例如,\<liao ,表示匹配以 liao 开头的单词。等价于 \bliao | \< | \< | 不支持 | 不支持,但是可以使用 \b 来匹配单词边界 |
\> | 匹配单词结尾处 | \> | \> | 不支持 | 不支持,但是可以使用 \b 来匹配单词边界 |
> | 匹配单词结尾处,这种元字符的含义有问题 | > | > | 不支持 | 不支持,但是可以使用 \b 来匹配单词边界 |
? | 匹配前面的子表达式 0 次或者 1 次;匹配前面的子表达式 0 个或 1 个;匹配 0 个或 1 个前面的子表达式;匹配 0 个或 1个前面的子表达式所代指的字符串;匹配 0 个或 1 个前面的子表达式所匹配到的字符串 | 不支持,需要转义 | ? | ? | ? |
\? | 匹配前面的子表达式 0 次或者 1 次,这种元字符的含义有问题 | \? | 不支持 | 不支持 | 不支持 |
? | 问号跟在任何一个量词后面,则变成非贪婪匹配模式。 | 不支持 | 不支持 | 不支持 | 不支持 |
. | 匹配除了换行符以外的任意一个字符(awk 指令中的句点 . 可以匹配换行符 \n ) | . | . (如果要匹配包含换行符在内的任意单个字符,可以使用 [\s\S] ) | . | . (如果要匹配包含 \n 在内的任意一个字符,可以使用 [.\n] ) |
* | 匹配前面的子表达式任意次;匹配前面的子表达式任意个;匹配任意次前面的子表达式 | * | * | * | * |
+ | 匹配前面的子表达式 1 次或者多次 | 需要转义 | + | + | + |
{n} | n 是一个非负整数,表示匹配前面的子表达式 n 次 | 需要转义,\{n\} | {n} | {n} | {n} |
x|y | 匹配 x 或者 y | 需要转义,x\|y | x|y | x|y | x|y |
\d | 匹配从 0 到 9 中的任意一个数字字符 | 不支持 | 不支持 | \d | \d |
\D | 匹配非数字的任意一个字符 | 不支持 | 不支持 | \D | \D |
\S | 匹配除了空白字符以外的任意一个字符 | 不支持 | 不支持 | \S | \S |
\s | 匹配任意一个空白字符,等价于 [\f\n\r\t\v] | 不支持 | 不支持 | \s | \s |
\W | 匹配除了英文字母、数字、下划线以外的任意一个字符 | \W | \W | \W | \W |
\w | 匹配英文字母、数字、下划线中的任意一个字符 | \w | \w | \w | \w |
\B | 匹配非单词边界,例如,er\B 可以匹配 here 中的 er ,但是不能匹配 hier 中的 er | \B | \B | \B | \B |
\b | 匹配单词边界 | \b | \b | \b | \b |
\f | 匹配一个换页符。等价于 \x0c 和 \cL | 不支持 | 不支持 | \f | \f |
\n | 匹配一个换行符。等价于 \x0a 和 \cJ | 不支持 | 不支持 | \n | \n |
\r | 匹配一个回车符。等价于 \x0d 和 \cM | 不支持 | 不支持 | \r | \r |
\t | 匹配一个横向制表符。等价于 \x09 和 \cI | 不支持 | 不支持 | \t | \t |
\v | 匹配一个垂直制表符。等价于 \x0b 和 \cK | 不支持 | 不支持 | \v | \v |
\cx | 匹配由 x 指明的控制字符。例如,\cM 匹配一个 Control-M 或回车符,x 的值必须为一个英文字母,否则 c 被视为一个普通字符 | 不支持 | 不支持 | \cx | |
\xn | 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,\x41 匹配 A 。正则表达式中可以使用 ASCII 编码。 | 不支持 | 不支持 | 支持 | |
\num | 其中 num 为一个正整数,表示对所获取的匹配的引用 | 不支持 | \num | \num |
注意:
- js 中支持的是 EREs。
- 当使用 BREs ( 基本正则表达式 ) 时,必须在下列这些符号
?,+,|,{,},(,)
前加上转义字符。
四、Linux/OS X 下常用命令与正则表达式的关系
我曾经尝试在 grep 和 sed 命令中书写正则表达式,经常发现某些元字符不能直接使用,有些需要转义,有些又不需要转义,下面就梳理了不同的命令所支持的正则表达式种类。
命令 | 正则表达式特定 |
---|---|
grep | 支持 BREs、EREs、PREs 正则表达式。 1. 指令后不跟任何参数, 则表示要使用 “BREs”; 2. grep 指令后跟 ”-E” 参数, 则表示要使用 “EREs”; 3. grep 指令后跟 “-P” 参数, 则表示要使用 “PREs”。 |
egrep | 支持 EREs、PREs 正则表达式。 1. egrep 指令后不跟任何参数, 则表示要使用 “EREs”; 2. egrep 指令后跟 “-P” 参数, 则表示要使用 “PREs”。 |
sed | 支持 BREs、EREs。 1. sed 指令默认是使用 “BREs”; 2. sed 指令后跟 “-r” 参数 , 则表示要使用“EREs”。 |
awk | 支持 EREs,并且默认使用 “EREs”。 |