最近京东图书在搞活动,就兴起买了几本书,包括余晟老师的《正则指引》,Unix经典书籍《Linux/Unix设计思想》等。我没有看过对《正则指引》这本书的评价,而是因为几个月前无意间在InfoQ上看到余晟老师发表的一篇文章《Linux/Unix工具与正则表达式的POSIX规范》,觉得总结概括的非常好,也解了我平时不少的疑惑,我也向几位朋友推荐过这篇文章。

有些人可能对正则表达式嗤之以鼻,认为它不易维护,晦涩难懂。事实上,他们会有这样的想法是因为对正则不了解(或者其它)。我一直坚信存在就是合理的,正则表达式的出现,并且在众多编程语言和许多工具中都得到支持,必然有它独具魅力的一面。假设你想检查一个邮箱地址是否合法,如果不用正则表达式,请问你会用什么来处理呢?自己编写一段复杂的字符串匹配的代码吗?若已用好的工具,何必再推倒重头再来,站在巨人的肩膀上,可以走得更远。

正则表达式是处理文本和字符串的利器,不过武器虽锋利,但是还是需要人用得好。我觉得正则表达式的长度不应该过长,短小则精悍,用《Linux/Unix设计思想》中的一条原则来说,则是“小即是美”。过长的正则表达式才真得会让人晦涩难懂,我估计即使写出这些正则表达式的人过段时间后也不见得能够解释清楚。例如针对URL地址的匹配,可以在网上找到很多人给出的正则表达式。其中,有些为了严格遵循标准定义的URL规范,给出的正则往往如天书般。我记得曾经看到过一个更加长的表达式,不过忘记地址了。相信看到这种表达式,大家都没有复制的兴趣了吧,有时候必须在功能和性能(或者可用性,可维护性)之间做出选择的。

回头继续说正则表达式,我一直对脚本编程非常感兴趣,而脚本语言往往对正则的支持比较好,例如Perl、Python等。因此,很早就接触了正则表达式。而今,因为工作的需要(运维),往往有更多机会用到正则表达式,这样可以节省我非常多的时间,并且得到的效果也是很好的。正则表达式发展到现在,事实上流派已经很多了。不同的语言不同的工具对正则的支持实现都不一样。我所接触过的,JavaScript中的正则相对比较弱,Python中的正则已经比较完善了,而像Linux下面的一些工具,例如sed、grep、vim等,它们所提供的正则一般和编程语言中的不大一样,即使工具之间也会有很多区别。

余晟老师的《正则指引》的第一章和《Linux/Unix工具与正则表达式的POSIX规范》文章中都有对正则表达式的流派总结过,最著名的是从Perl衍生出来的PCRE(Per Compatible Regular Expression)规范和POSIX(Portable Operating System Interface for Unix)规范定义的正则规范。而后者又分为BRE(Basic Regular Expression)和ERE(Extended Regular Express)两大流派。前者的代表是grep/sed等,而后者的代表则是grep -E/sed -r/awk等。所以像grep和sed这两个命令,对两种流派都是支持的。BRE和ERE的一个显著区别是,BRE需要对一些特殊字符进行转义,例如在ERE中可以使用'|'、'+'、'?',而在BRE中则需要转义才能正常使用,例如'\|'、'\+'、'\?'。

看书后还有很多收获的东西,以前我不知道POSIX正则规范中在字符组中的元字符是是没有特殊含义的,例如:

$ echo '\n' | grep -E '[\n]'
\n
$ echo '*' | grep -E '[*]'
*
$ echo '?' | grep -E '[?]'
?

所以在PCRE兼容的正则表达式中'[\d]'会匹配数字,而按照POSIX正则规范的定义,'[\d]'的意思就是匹配'\'或者'd'两个字符。还有一点是,如果匹配'[]',只需要转义开始的'['符号就行:

$ echo '[a]' | grep '\[a]'
[a]

现在发现自己好多东西都是从网上自学而来的,难免有一些概念是夹杂着自己的理解,有时候这些理解是错误的,就需要好好看看别人写的书,希望有更多空闲时间可以好好看书。