ERE正则引擎

扩展正则表达式(Extended Regular Expression)在BRE的基础上,进行了功能上的扩充,增加了元字符。

在Linux中,常见的使用ERE正则的程序有grep -E|egrepsed -r,awk等。

ERE的元字符

和BRE的元字符完全相同,在此之上,新增了元字符。

(),{}在BRE正则中需要配合\使用(\(\),\{\}),在ERE中不再需要转义字符。 增加了+,?,|这三个元字符。

元字符 描述
+ 代表前面一个字符至少匹配一次,匹配次数无上限,如1+匹配1,11,111...
? 代表前面一个字符至多匹配一次,如a?b代表匹配bab
| 选择匹配,类似于[pattern],代表连接的单词任选其一匹配,通常配合()使用,如(cat|dog)
() 用于分组(后祥),本身不匹配任何字符,将模式进行分组,进行整组匹配或反向引用。如(cat)?代表cat这个单词至多出现1次。
{} 限制匹配次数{m,n}代表前面的字符至少匹配m次,至多匹配n次。m或n省略代表这个边界不限。如{,1}等同于?,{1,}等同于+{n}代表匹配n次

TIPS: |两端不要有空格,(|)的作用是限制|连接的范围。

ERE正则的运用

例如匹配date +%F的时间格式:

date +%F | grep -E '^[0-9]{4}-[01][0-9]-[0-3][0-9]$'  # 注意,不要把合法性判断放在这里

这段正则是我在下载腾讯漫画的脚本中应用的, 用于判断用户输入的章节列表格式是否合法,猜猜看,这段这则想要匹配的字符串格式是什么?

    ^\d+([,-]\d+)*$

同样没有用正则对用户输入的合法性做判断,而是在后面的逻辑代码中才对这些范围做判断。

看看这个正则,用于nginx匹配tomcat的静态资源路径:

^/(static/)?(css|fonts|images|img|js)

TIPS: 在一定复杂度的前提下,正则写的越确切越好,意味着出意外的可能性就越小。

*+的原罪 —— 贪婪匹配

*+在正则引擎中,会尽可能多的匹配满足条件的pattern,此外,还有{},? 也满足这个规律。这种规律称为贪婪匹配(greedy matching)。

比如想对HTML标签进行匹配:

echo 'aa<div>test1</div>bb<div>test2</div>cc' | grep -oE '<div>.+</div>'
<div>test1</div>bb<div>test2</div>

这种结果可能是致命的——并不是本意,可能造成无法预估的BUG。

遗憾的是,BER引擎和ERE引擎诞生较早,并不支持非贪婪匹配(lazy matching)。

后续的正则引擎(如Perl的PCRE)支持了非贪婪模式。在贪婪模式的后面加上?即可进入非贪婪模式。

echo 'aa<div>test1</div>bb<div>test2</div>cc' | grep -oP '<div>.+?</div>'
<div>test1</div>
<div>test2</div>

TIPS: 正则不适合处理这种标记性文档,会让正则很复杂,难以维护,也不能很好的处理标签嵌套的问题。 建议使用现成的类库做解析。

猜猜看,对于这个字符串copyright 2003.,用正则^.*[0-9]+去匹配,匹配到的是什么结果?

小练习

  1. 试写出一个正则,匹配十进制数字(正负数,整数,小数,科学计数法),并用grep/sed验证你的结果。

如:

5
-5
+5
1.111111
-10.5
1.1E5
2.2e-5
  1. 删除HTML页面中全部的HTML标签,只保留纯文本部分,如何实现?用相关命令验证你的正则 (也可以用编程语言实现,暂不考虑复杂的情况,假定每个标签都在单独一行,没有出现跨行标签,比如师傅到首页)