BT

您是否属于早期采用者或者创新人士?InfoQ正在努力为您设计更多新功能。了解更多

刨根究底正则表达式之一:正则表达式概述

| 作者 林耀平(笨笨阿林) 关注 1 他的粉丝 发布于 2017年7月11日. 估计阅读时间: 2 分钟 | 硅谷人工智能、机器学习、互联网金融、未来移动技术架构 ,尽在QCon上海2017

一、缘起

计算机世界中有一些非常基础、重要、应用广泛而又特别容易让人困惑的主题,这包括字符编码、字节序(即大小端表示)、正则表达式以及浮点数实现、日期时间处理等等。其中,字节序、正则表达式跟字符编码的关系非常密切。字符编码以及字节序的问题我已经在另一个系列文章《刨根究底字符编码》中介绍过了,这个系列来讨论正则表达式。

不同于字符编码竟然连一本专著都没有的尴尬,正则表达式目前市面上并不缺乏专业著作,比如那本被誉为正则表达式学习圣经的《精通正则表达式》就很值得一读,另外该书的译者余晟先生所写的《正则指引》也不错;如果仅用于入门,则《正则表达式必知必会》肯定不能错过,还有网上流传极广的《正则表达式30分钟入门教程》也是不错的入门资料。

但是,结合我自身痛苦的正则表达式学习经历和运用体会,仅有这些是远远不够的。记得被大家称之为“轮子哥”的大神级程序员vczh在知乎上说过,当初被正则表达式虐得一气之下,干脆自己写了一个正则引擎(源码托管在Github上),才算真正彻底搞懂正则表达式(于是被戏称为“一言不合”就造轮子)。当然不是每个程序员都能如此生猛,但即便都有这么生猛,似乎也没必要都像“轮子哥”这样自己再造一个“轮子”。

那到底应该怎样才能最高性价比地掌握正则表达式这个神器呢?这正是我写这个系列文章的目的。

正则表达式是典型的那种没用过的话,不觉得对自己有什么影响,可是一旦用过了,就再也回不去了的神器。当然,我这里所说的“用过”,不是指简单用用一些基本功能,而是指能够熟练运用其基本功能和高级功能。用得越熟练,就会越惊叹于其强大与神奇。

看到这里,我相信某些学过正则表达式、会使用一些基本功能的童鞋,心里或许在犯嘀咕了:神器是神器,可这玩意儿看起来就像天书一样,也太难学、太难懂了,要达到熟练运用的程度,谈何容易!短短的一个正则表达式,或许不到10个字符,其中的每个字符都认识,但连在一起,却越看越迷惑,越想越迷糊……

是的,正则表达式既然被捧上了神器级别的高度,自然是有着相当强大的功能,这当然就意味着其有非常深厚的内涵,也就意味着有很多需要注意的细节。

注意,我这里没有说正则表达式是由于复杂而难以理解,这是因为,深厚的内涵不等于复杂,细节很多不意味着难以理解。看到这里,或许有人有意见了,正则表达式还不算复杂?还不够难理解?你秀智商呢,还是秀优越感呢?哦,相信我,其实这两者我都不太沾边。智商我也只是中等而已,否则早就不在这里码字了;而优越感则更提不上——既不高也不富更不帅,何来优越感?!

其实,我真正想说的是,繁复或许是真的,杂乱倒未必。因此,简单地说正则表达式复杂,似乎不够准确而客观。正如跟一个牛叉而又性格独特(废话,真正牛叉的人基本上都有独特的性格)的人打交道,关键不在于纠结其性格的独特、脾气的古怪,而是重在充分了解并理解其独特的性格、古怪的脾气,然后在此基础上与他/她进行良好的沟通,以便能好好发挥其牛叉之处。

学习并熟练掌握正则表达式的过程也是如此——关键在于先要摸透其“性格”到底独特在哪里,其“脾气”又究竟古怪在何方。一旦摸清楚了其“性格”,其“脾气”,学习起来就事半功倍了。

因此,我下面准备从我自己的角度,先尝试着来分析一下正则表达式那独特的“性格”与古怪的“脾气”,看看究竟为什么正则表达式给那么多人的感觉都是那么难以“亲近”。

二、正则表达式为什么难学?

对于正则表达式的分析和解读,目前大多数文章和书籍多集中在正则表达式自身,比如对正则表达式的各个元字符、元转义序列以及匹配原理的分析和解读上。

当然,这些自然也是很有必要的,而且是学习的主要内容,是理解正则表达式所必需的。然而,很多人在看了大量这类文章和书籍之后,仍然觉得正则表达式很难看懂,不好理解,经常有一种智商被碾压的即视感。

难道真的是正则表达式的学习者智商不够吗?其实,理解一个事物,都应该有两个维度,或者说两个层面

,深入该事物本身里面去理解

二是,跳出到该事物外面,站在更高的一个维度或层面来理解。

正如苏轼那首著名的哲理诗《题西林壁》所说的,“不识庐山真面目,只缘身在此山中”。很多时候往往是这样,当你只从该事物本身来看的话,就如在云里雾里,是远远不够的;而一旦跳出到该事物之外,站在更高的一个角度来看,则又正如王安石的《登飞来峰》中所说:“不畏浮云遮望眼,只缘身在最高层”。

对正则表达式而言,前者正是目前大多数文章和书籍在做的;而后者,却很少有文章和书籍能够跳出正则表达式,站在更高的维度或层面来分析和解读正则表达式。这里就包括了《精通正则表达式》和《正则指引》两书。

这里需要特别强调一下的是,我绝没有贬低上述这两本专著及其作者和/或译者之意,而且恰恰相反,这两本专著正是本系列文章的重要参考书。尤其无论是作为《精通正则表达式》的译者,还是作为《正则指引》的著者,余晟先生都绝对称得上是专业而又严谨的。

那么前面所谓“更高的维度或层面,到底指的是什么呢?那就是,从编程语言发展史以及编程范式的角度来看正则表达式。什么?正则表达式竟然算得上是一门正式编程语言吗?别急,请继续往下看。

正则表达式有一个非常明显的特点:高度简洁、高度抽象。正则表达式中短短几个字符,或许就代表了一段复杂的处理逻辑和匹配算法。

我们知道,程序代码是对现实事务处理逻辑的抽象,而正则表达式则是对复杂的字符匹配程序代码的进一步抽象;也就是说,高度简洁的正则表达式,可以认为其背后所对应的是字符匹配程序代码,而字符匹配程序代码,背后对应的是字符匹配处理逻辑。

因此可以这么认为,字符匹配处理逻辑,抽象为字符匹配程序代码;字符匹配程序代码,再进一步抽象为高度简洁的正则表达式。

所以说,高度简洁的正则表达式是高度抽象的。

事实上,从编程语言发展的角度来看,正则表达式也是一种编程语言,而且是属于第4代语言(4GL)——面向问题语言(第1代语言为机器语言——由0和1组成的位串,第2代语言为汇编语言——用接近于英语单词的助记码mnemonic code来代替由0和1组成的位串,第3代语言为高级语言——用接近于自然语言的语法元素编写程序,如C/C++、Java、C#、Perl、Python、PHP、JavaScript等语言,第4代语言为面向问题语言——用针对问题领域专门设计的语法元素编写程序或表达式,如SQL、SAS、SPSS、LaTeX、Regex(即正则表达式)等,第5代语言为人工智能语言——Prolog、Mercury、OPS5等;不过,从第4代语言到第5代语言的演化还不是很清晰,目前学术界争议较大,这里不作讨论)。

第4代语言相对于第3代语言,更专注于其所应用或者说其所适用的某个特定的业务逻辑和问题领域。程序员主要负责分析问题,以及使用第4代语言来描述问题,而无需花费大量时间去考虑具体的处理逻辑和算法实现(事实上,最初之所以提出第4代语言的概念,就是希望非专业程序员也能做应用开发)。

编程范式(programming paradigm)的角度上来讲,第4代语言属于声明式编程范式(Declarative programming paradigm),声明式编程重在目标而非过程、重在描述而非实现,以声明式语句直接描述问题,专注于问题的分析和表达,而非专注于处理逻辑和算法实现过程,其具体的处理逻辑和算法实现是由语言解析引擎(编译器或解释器)来负责的。

当然,这样一来,这些由语言解析引擎实现的处理逻辑和具体算法其通用性就会较差,只能适用于某些特定业务或特定领域。也正是这个原因,第4代语言基本都是局限于某些特定领域的,多被认为是领域特定语言DSL(Domain Specific Language)

区别于算法实现可由程序员自由灵活设计的通用编程语言GPPL(General-Purpose Programming Language,作为第3代语言的高级语言基本上都属于通用编程语言)领域特定语言DSL的算法基本上由语言解析引擎自动实现,程序员灵活设计、自由发挥的空间很小,因此DSL几乎没有通用性(而且DSL大都是非图灵完备的语言),只能专用于解决特定业务方向和业务领域的问题。

比如,SQL是专用于数据库操作的语言、SAS和SPSS是专用于统计分析的语言、LaTeX是专用于排版的语言,而正则表达式Regex(regular expression)则是专用于处理字符匹配的语言

理解了这一点,就比较容易理解正则表达式是字符匹配处理逻辑的抽象;更进一步地来说,正则表达式中的某些元字符与特殊结构,可理解为某种具体的程序逻辑和算法的体现。

比如,正则表达式中的量词*这一元字符,就是高级语言的处理逻辑“循环结构”的体现(具体来说量词*代表的是不定次数循环),而前后多个量词的嵌套就是多层循环的嵌套;或运算符|这一元字符,就是高级语言的处理逻辑“选择结构”的体现。

而当或运算符|出现在由量词*所限定的圆括号中时,其实就是在“循环结构”中嵌套了“选择结构”;而如果进一步地,“循环结构”所嵌套的“选择结构”中的某个分支,又被某个量词*所限定,那么则相当于“循环结构”所嵌套的“选择结构”又嵌套了“循环结构”。

理解这一点非常重要,是快速、深入理解正则表达式的一把钥匙、一条捷径。站在编程语言发展史编程范式的高度,再结合对正则表达式本身原理的深入理解,里外结合,高下相较既登高望远、一览众山小,又洞幽烛微、复观千水深,正则表达式的奥义,就尽在掌握中了

当然,正则表达式之所以难学、难理解,除了由于正则表达式作为一个字符匹配领域的领域特定语言(DSL),具有高度简洁、高度抽象的特点之外,大致上应该还有以下几个原因:

1) 学习者不求甚解,不了解正则引擎内部的基本原理

作为正则表达式的使用者,不需要深入了解正则引擎内部原理的技术实现细节,那是正则引擎开发者更应该了解的;但若完全不了解其基本工作原理和运行机制,也是不足取的。

2) 多个多义元字符,特别容易使人混淆迷乱

比如-、+、?、^,尤其是元字符?,既可以作为量词表示其所限定的子表达式为可选(即匹配0次或1次),也可以置于量词之后表示懒惰匹配,而且还有很多特殊分组结构中用到它,比如(?<name>sub-regex)、(?:sub-regex)、(?>sub-regex)、(?=sub-regex)、(?!sub-regex)、(?<=sub-regex)、(?<!sub-regex)、(?|sub-regex)、(?modifier-modifier)、(?(condition)|)、(?R)、(?num)、(?#comment)等;还记得我自己当初刚开始学习的时候,一看到正则表达式中的问号?,就有一种独自在风中凌乱的感觉。

3) 转义也是难点

什么情况下需要转义,什么情况下不需要转义,貌似复杂得令人抓狂;当然,其实是有一定的规律的,掌握了这些规律,再遇到转义问题,就不至于心潮澎湃了。

4) 学习期望与学习方法不对

不应该期望一次性记住、学会并熟练运用,正确的学习姿势应该是:先简单入门,对一些基本的规则与元字符大致了解一遍,有个印象就好,在需要时再回过头来看,不用刻意去强行记忆;然后接下来就应该多练、多实践、多运用,边学、边深入、边熟练。

5) 用于入门的好教程、备忘单,也有用于深入的大部头专著但却缺乏好的速查手册

由于需要边学、边深入、边熟练,因此,平时手头边更需要的不是简单的入门教程、备忘单(Cheat Sheet),也不仅仅是知识点分散于各处的大部头专著(知识点分散导致查找起来不方便,用于深入学习原理是不错,但不够实用),而是一本按语法元素将知识点综合在一起进行编排的、在需要回过头来看时能够随时快速翻查的速查手册。这样,在实践运用中遇到问题就可方便随时快速翻查,而这一点恰恰对于正则表达式这种不可能短期内快速掌握并熟练运用的专业工具的学习与使用非常重要。

6) 没有使用好的学习工具

你知道regex101.com、RegexBuddy、regexper.com等正则表达式的专业网站和专业工具吗?这些堪称学习正则表达式的神器,可令学习事半功倍,但很多人不知道,或知道但很少使用。

(点击放大图像)

正则表达式可视化工具(regexper.com)

三、正则表达式概念

一)先从“通配符”说起

对于初学者而言,正则表达式,仅从字面上来说不太好理解。但实际上,您可能早已经使用过了某些正则表达式的功能,只是自己还没有意识到而已。

因此,所谓“通配符”,即“通用匹配字符”,就是用某个通用字符按事先所规定的规则来查找匹配某些常规字符,从而实现“以一对多”(或“以一代多”)、“以简对繁”(或“以简代繁”)地简化、抽象化、通用化用来进行查找匹配的表达式的目的。

然而,尽管使用“通配符”的匹配查找方法很有用,但它的功能还是非常有限的。和通配符类似,正则表达式也是用来进行文本匹配查找的工具。只不过相比通配符而言,正则表达式更为抽象化、通用化,功能也更为强大、更加灵活,能够更为精确地表达匹配条件(即匹配规则),当然也就更复杂,更难以学习和掌握。

二)正则表达式概念

正则表达式,又称正规表示法、常规表示法(Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。

正则表达式是一种字符串的匹配模式,描述的是某一类字符串的共同特征。

所谓模式,就是模板样式或模具样式。正如符合某种样式的模板或模具,可以用来生产符合这种样式的同一类产品一样;反过来,也可以用某种样式的模板或模具,来检验或框定哪些产品才是符合这种样式的同一类产品。

正则表达式正是类似于这样的模板或模具,用来检验或框定哪些字符串是符合正则表达式所描述的字符串共同特征的同一类字符串;而这个检验或框定的过程,就称之为匹配

我们平时所使用的自然语言中,可以用“漂亮”、“坚固”、“挺拔”等高度抽象性词语来描述事物的共同特征一样,一个正则表达式正是某一类字符串的高度抽象,用来描述这类字符串的共同特征。也就是说,一个正则表达式代表了某类字符串的一个集合,而正则表达式相当于对该字符串集合的特征性质描述。(注:集合的常用表示方法有元素列举法、特征性质描述法和图示法。)

正则表达式还可看作是对字符串操作的一种逻辑公式,其构造方法和创建数学表达式的方法差不多,也就是用普通字符(如字母a到z、数字0到9等)和事先定义好的一些特定字符(专业术语称之为元字符),以及这些字符的组合,组成一个特定的规则字符串。而所谓特定的规则即是正则因此特定规则字符串,即是正则表达式。

这些“特定的规则”,从被匹配的字符串的角度上来看,可以认为描述的是某一类字符串的共同特征;正则表达式的角度上来也可以认为表达的一种匹配规则(或过滤逻辑)。

因此,正则表达式是一种特殊的字符串(即正则表达式字符串,往往直接简称为正则表达式或正则式)用来描述、匹配、过滤符合某些特征的其它字符串(即输入字符串、源字符串测试的字符串、匹配的字符串,往往直接简称字符串)

说某个正则表达式匹配某个字符串,通常是指这个字符串的全部或一部分或几部分分别符合或者说满足正则表达式所描述的字符串特征;也可以说是指这个字符串的全部或一部分或几部分分别符合或者说满足正则表达式所规定的匹配条件或匹配规则。

而从正则表达式作为一种编程语言的角度上来看,正则表达式的基本语法结构与一般高级编程语言差不多,主要就是顺序(即连接)、选择(即分支)、循环(即重复)三种,其他都是这三者的组合,再加上一些语法糖。

再更进一步地,从正则表达式作为一个声明式编程范式领域特定语言DSL的角度来讲,正则表达式的顺序、选择、循环这三种基本语法结构是非常简洁、紧凑的(这几乎是声明范式DSL的基本特点,而正则表达式将这一点体现得尤为淋漓尽致)。其中,连接无需通过元字符表示,选择通过元字符“|”表示,而循环则通过元字符“*”、“+”或“{n,m}”表示。这三种基本语法结构在使用时,直接进行声明式描述即可,无需通过复杂的语句来进行算法设计。

事实上,还可从编程语言操作符(即运算符)的角度来理解,其中,“*”、“+”或“{n,m}”是单目后缀操作符,“|”是双目中缀操作符,连接其实也是双目中缀操作符,不过是隐含的(即隐式的,因为连接是三种基本语法结构中最常用的,所以设计为隐式操作符最为合理)。

、正则表达式功能

一般而言,典型的简单搜索和替换操作,可通过直接提供与预期的搜索结果相匹配的字面文本来实现。虽然这种方法对于文本执行简单的、静态的搜索和替换任务可能已经足够了,然而却缺乏足够的灵活性和动态性。

若通过使用正则表达式,则可以:

  • 查找文本
  • 提取文本
  • 验证文本
  • 替换文本
  • 切分文本

显然,通过使用文本模式,正则表达式相比较于直接使用固定的、明确的字面文本进行简单的、静态的搜索和替换,更为灵活,也更具有动态适应性。而且,正则表达式同样也可以使用字面文本进行简单的、静态的搜索和替换(当然,这有点大材小用了,效率也比直接搜索和替换更低,因此,字面文本的直接搜索和替换,不推荐使用正则表达式)。

因此,正则表达式的熟练运用,是文本处理人员,尤其是编程人员的必备技能。其强大的功能、快捷的速度,一旦掌握,你将会既叹服于心,又享受其中。

五、正则表达式简史

正则表达式的“祖先”可以一直追溯至对人类神经系统如何工作的早期研究。Warren McCulloch和Walter Pitts这两位神经生理学家在20世纪40年代研究出用一种数学方式来描述神经网络。

1956年,一位叫Stephen Kleene的数学家在McCulloch和Pitts早期工作的基础上,发表了一篇标题为《神经网络事件表示法和有穷自动机(Representation of events in nerve nets and finite automata)》的论文,引入了正则表达式的概念。正则表达式就是用来描述他称为“正则集合Regular Sets”的表达式,这就是“正则表达式”这个术语的来源。

随后,大名鼎鼎的Unix之父——Ken Thompson于1968年发表了文章《正则表达式搜索算法(Regular Expression Search Algorithm)》,并且将正则表达式这一符号系统引入了他自己开发的编辑器qed以及之后的编辑器ed中,然后又被移植到了大名鼎鼎的文本搜索工具grep中。自此,正则表达式被广泛应用到各种Unix系统或类Unix系统(如Mac系统、Linux系统)的工具中。

由于正则表达式异常强大而实用的功能,越来越多的语言和工具引入了正则表达式。不过遗憾的是,始终没有确立正则表达式方面的标准,导致各语言与工具中的正则表达式虽然功能上大体类似,但细微差别仍然不少。于是,诞生于1986年的POSIX开始进行标准化的尝试。

POSIX,是Portable Operating System Interface for uniX(可移植Unix操作系统接口)的缩写。POSIX是一系列规范,定义了Unix操作系统应当支持的功能,其中也包括正则表达式的规范。

因此,Unix系统或类Unix系统上的大部分工具,如grep、sed、awk等,均遵循该标准。遵循POSIX正则表达式规范的这些语言和工具中的正则引擎,往往习惯将它们称之为POSIX流派的正则引擎。

之后,1988年6月,Larry Wall开发的Perl语言发布第2版,其中所引入的正则表达式引擎大放异彩。Perl 2的正则表达式引擎源于Henry Spencer编写的regex的增强版。之后不断改进,影响越来越大。于是在此基础上,1997年又诞生了pcre——Perl兼容正则表达式(Perl Compatible Regular Expressions)。

PCRE是一个由Philip Hazel开发的、为很多现代语言和工具所普遍使用的Perl正则表达式兼容引擎,现已成为除了Unix上的工具所遵循的POSIX标准之外的其他大部分语言和工具所隐然遵循的另一个事实上的标准。因此,往往习惯将这些Perl正则表达式兼容引擎称之为PCRE流派的正则引擎。

POSIX流派与PCRE流派是目前正则表达式引擎流派中的两大最主要的流派。

之后,正则表达式在各种计算机语言或各种应用领域进一步得到了更为广泛而普遍的应用和发展。

六、正则表达式流派

如前所述,目前正则表达式主要有两大流派(Flavor):POSIX流派与PCRE流派。

1)POSIX(Portable Operating System Interface for uniX)流派

POSIX是一系列规范,定义了UNIX操作系统应当支持的功能,其中也包括正则表达式的规范。POSIX规范的正则表达式流派是PCRE之外的另一大流派。

POSIX规范定义了正则表达式的BRE(Basic Regular Expression基本正则表达式)和ERE(Extended Regular Express扩展正则表达式)两种标准。早期,BRE与ERE的区别主要在于:

不过,后来随着BRE与ERE逐渐相互融合,现在的BRE和ERE(包括GNU改进的GNU BRE和GNU ERE)在功能特性上并没有太大区别,主要的差异是在元字符的转义上。

在遵循POSIX规范的UNIX/LINUX系统上,vi/vim、grep和sed遵循POSIX规范的BRE标准,egrep、awk则遵循ERE标准。这些UNIX/LINUX系统常用工具的正则表示法与PCRE对比如下:

注1:vim中的\?和\=都表示匹配0或1个前面的子表达式,但\?不能在反向查找的“?”命令中使用。

注2:vim中的右花括号}之前可以不加反斜杠,也可以加反斜杠,比如:\{n,m\}。

注3:PCRE中常用\b来表示“单词的起始或结束位置”,但Linux/Unix的工具中,通常用\<来匹配“单词的起始位置”,用\>来匹配“单词的结束位置”,而sed中的\y则与PCRE中的\b一样,可同时匹配这两个位置。

2)PCRE(Perl Compatible Regular Expression)流派

目前大部分常用编程语言中常见的正则表达式语法,其实都源于Perl。其中,PCRE就是从Perl衍生出来的最为著名的一个流派,\d、\w、\s之类的字符组简记法,是这个流派的显著特征。

不过,虽然PCRE流派是从Perl语言中衍生出来的,但与Perl语言的正则表达式还是有一些细微差异的,比如PHP的preg(Perl Regular Expression)与Perl的差异可看这里

PHP支持两种不同的正则引擎:ereg与preg,ereg全称为Extended Regular Expression,属于POSIX ERE;ereg由于功能方面的不足,已经逐渐被preg替代了,ereg将在未来被废弃。因此,若非特别说明,后文中当提到PHP正则引擎时,默认指的是PHP preg正则引擎。)

考虑到目前绝大部分常用编程语言所采用的正则引擎基本属于PCRE流派,因此,本系列文章将以PCRE流派为主、以POSIX流派为辅进行介绍;文中有关各语法元素的解释,若非特别说明,均以PCRE流派为准。

另外,如前所述,当我们在介绍正则表达式的流派时,与Perl正则规范相兼容(包括直接兼容与间接兼容)的流派习惯用PCRE来称呼。

而本系列文章在介绍与Perl正则规范直接兼容(但除Perl外并非完全兼容)的语言或正则库或工具程序,比如Perl、PHP preg、PCRE库时,一般称之为Perl系;与之对应的还有间接兼容的Java系(包括Java、Groovy、Scala等)、.Net系(包括C#、VB.Net)、Python系(包括Python2和Python3)、JavaScript系(包括原生JavaScript和扩展库XRegExp)等等。

也就是说,Perl系、Java系、.Net系、Python系、JavaScript系(另外还有Ruby、C++Builder、Delphi等)均属于PCRE流派,但与Perl的兼容性(即兼容程度)各有不同。其中,Perl系兼容性最好,虽然PHP preg与PRCE库并非与Perl完全兼容,但基本兼容,因此属于直接兼容;而其他语言或工具相对Perl系而言,与Perl的兼容性较差,则属于间接兼容。

七、本系列文章的体例及后续内容

本系列文章出自于我自己在学习正则表达式的过程中所经历过的真切体会和真实痛点。因此,正如前面所述,采取的编排风格会类似于速查手册。不过,与一般的仅供入门使用的字典式简易手册不同,这将会是一本更为深入的专业级速查手册。这也正是文章名称中特别强调“刨根究底”,而不是直接名之为速查手册、快速参考之类的原因。

本系列文章当然会涉及到正则引擎内部的相关匹配原理与匹配机制的解释(而且还独创性地总结为了八大原则,便于“以简驭繁”、“提纲挈领”地快速掌握要领以便于记忆和理解),只是与其他专著用专门章节进行介绍不同,而是各自糅合于对相关语法元素的解释之中了。

这种为了便于快速翻查而没有将匹配原理与匹配机制予以专章介绍的特殊编排,自然也有其缺点(比如,你可能会在不同的语法元素中发现类似的雷同解释,这或许有重复啰嗦之嫌,但毕竟这符合我们的编排目的),但问题在于市面上进行专章介绍的专著已经有很多了,再重复它们意义不大;而专门针对前述的正则表达式学习和运用痛点的文章和专著则基本没有,而这正是本系列文章的意义和目的所在。

也因此,出于更偏向于实践运用的目的,本系列文章不会花费过多的笔墨在DFA、NFA等过于深入的正则表达式幕后技术细节的讲解上。事实上,我认为只要大致了解它们的基本原理与工作机制以及两者之间在功能特性上的差异,就完全可以熟练掌握并运用正则表达式了,除非你是想自己开发一个正则引擎,实在没必要陷入DFA、NFA等的技术实现细节中。

我相信通过反复阅读本系列文章,再多加练习、勤于实践,然后在实际运用时再不断回过头来随时翻看,应该完全可以熟练掌握这个像毒品一样会让人上瘾的神器。

最后,再说一下本系列文章后续将会涉及到的内容:首先会大致简单介绍一下正则表达式语法基础,接下来对元字符、元转义序列、特殊构造(特殊结构)等正则表达式的语法元素进行逐个详解;之后,再讲解一下匹配模式、POSIX字符组方括号表达式以及字符组运算;最后是正则表达式各语法元素优先级介绍。

参考资料

一) 官方文档

Perl:

PCRE:

PHP:

.Net(C#、VB):

Java:

JavaScript:

Python2.7:

  1. 正则表达式操作(中文)
  2. Regular expression operations(英文)

Python3.4:

Ruby:

Vim:

GNU Grep:

GNU Sed:

GNU awk:

二) 书籍

三) 其他

本系列文章还参考了网上的大量资料,除了少部分资料由于未作大量修改(但基本上也有少量修改,因为网上文章随意性较大,很多明显的笔误或前后矛盾之处,如若不改反而让人迷糊)而标明了原作者和出处之外,其余由于基本上已按自己的理解作了大量改写,因此没有再一一予以说明,在此对原文作者表示歉意并感谢。

另外,文中图片小部分来自网络,大部分为本人制作,也不再一一说明,在此对原图作者表示歉意并感谢。


感谢杜小芳对本文的审校。

给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们。

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT