大数据和AI不分家,AI助力低代码和智能运维落地,AI智能体的探索实践,本届AS会议一站聚齐!>>> 了解详情
写点什么

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

  • 林耀平(笨笨阿林)

  • 2017-07-10
  • 本文字数:11017 字

    阅读完需:约 36 分钟

一、缘起

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

不同于字符编码竟然连一本专著都没有的尴尬,正则表达式目前市面上并不缺乏专业著作,比如那本被誉为正则表达式学习圣经的《精通正则表达式》就很值得一读,另外该书的译者余晟先生所写的《正则指引》也不错;如果仅用于入门,则《正则表达式必知必会》肯定不能错过,还有网上流传极广的《 正则表达式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 p**rogramming 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 次),也可以置于量词之后表示懒惰匹配,而且还有很多特殊分组结构中用到它,比如 (?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:

  • Perl regular expressions (perlre)(英文)
  • Perl Regular Expressions Reference (perlreref)(英文)
  • Perl Regular Expression Backslash Sequences and Escapes (perlrebackslash)(英文)
  • Perl Regular Expression Character Classes (perlrecharclass)(英文)

PCRE:

  • pcre2 syntax man page(英文)

PHP:

  • PCRE(preg) 正则表达式语法介绍 (中文)

.Net(C#、VB):

  • 正则表达式语言快速参考 (中文)

Java:

  • Regular Expressions Tutorials(英文)
  • Package java.util.regex(英文)

JavaScript:

  • MDN:正则表达式简介 (中文)
  • MDN:RegExp 对象说明 (中文)
  • EMCAScript:RegExp (Regular Expression) Objects(英文)

Python2.7:

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

Python3.4:

  • Regular expression operations(英文)
  • Regular expression HOWTO(英文)

Ruby:

  • Regular Expressions(英文)

Vim:

  • 模式及查找命令 For Vim version 7.4(中文)
  • Search commands and patterns For Vim version 7.3(英文)

GNU Grep:

  • Regular Expressions(英文)

GNU Sed:

  • Regular Expressions(英文)

GNU awk:

  • Regular Expressions(英文)

二) 书籍

  • 《 精通正则表达式》英文版及中文版 作者:Jeffrey E·F·Friedl 译者:余晟 电子工业出版社 2012-07
  • 《 正则指引》作者:余晟 电子工业出版社 2012-05
  • 《 正则表达式必知必会》作者:Ben Forta 译者:杨涛 人民邮电出版社 2015-01
  • 《 冒号课堂:编程范式与 OOP 思想》作者:郑晖 电子工业出版社 2009-10

三) 其他

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

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


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

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

2017-07-10 17:484725
最佳实践 语言 & 开发 架构 操作系统 编程语言 工业

评论

发布
暂无评论
  • 现年 80 岁的 Unix 大神还在修复 AWK 代码

    Unix 文本分析工具 AWK 添加了 Unicode 支持。

    语言 & 开发 开源 文化 & 方法 Linux GitHub 操作系统
  • InterpreterPattern- 解释器模式

    解释器模式(Interpreter Pattern):是指给定一门语言,定义它的文法的一种表示(如:加减乘除表达式和正则表达式等),然后再定义一个解释器,该解释器用来解释我们的文法表示(表达式)。

    2022-06-06

  • 10 种最具影响力的编程语言

    让我们来讨论一下那些“几乎已经消亡”的语言,以及它们如此重要的原因。

    编程语言 Java 性能优化 框架 工业 企业动态
  • 语法面面观:模式匹配

    2020-10-09

  • 解析器眼中的 Go 语言

    代码其实就是按照约定格式编写的一堆字符串

    文化 & 方法 语言 & 开发 方法论 编程语言
  • 正则表达式基础,记得把每一次面试当做经验积累

    正则表达式: "a.c\."

    2021-11-06

  • 春节策划第 2 期 | 读书如抽丝,为你推荐一些我读过的好书

    在专栏更新的过程中,有一些同学留言想要我推荐一些金融系统相关的图书,所以我为你精心梳理了一份书单,希望对你有所帮助。

    2021-02-15

  • 08|正则表达式:如何提高搜索内容的精确度?

    如果领导让你搜索出一个文档里所有的手机号码, 而你只知道手机号的模式是11位数字,那该怎样搜索呢?

    2021-02-27

  • 关于 GaussDB(DWS) 的正则表达式知多少?人人都能看得懂的详解来了!

    摘要:GaussDB(DWS)除了支持标准的POSIX正则表达式句法,还拥有一些特殊句法和选项,这些你可了解?本文便为你讲解这些特殊句法和选项。

    2021-02-23

  • 现代语言学之父乔姆斯基谈深度学习的未来

    越来越多的证据表明,人工神经网络并不能准确地模拟人类认知。

    AI&大模型 文化 & 方法 大数据 机器学习/深度学习 编程语言
  • JavaScript 学习(十)--- 正则表达式

    JavaScript 当年入门时的笔记,欢迎后来者来借鉴指点

    2021-06-26

  • 谈谈 DSL 以及 DSL 的应用(以 CocoaPods 为例)

    最近在公司做了一次有关 DSL 在 iOS 开发中的应用的分享

    语言 & 开发 文化 & 方法 方法论 编程语言 框架 企业动态
  • 五分钟搞定正则表达式,如果没搞定,再加两分钟,flutter 小程序实现

    是不是有些理解 "|" 的使用了呢。

    2021-11-02

  • 07|正则表达式:实现文件内容的搜索和替换

    今天我们来看一下如何利用 Vim 在一个文件中搜索和替换内容,其核心主题就是正则表达式。

    2020-08-07

  • 结束语|Vim 森林探秘,一切才刚刚开始

    《Vim 实用技巧必知必会》课程结束了,而你的学习旅程,到这儿只能算是一个小小的休息站。接下来,要靠你自己去探索。

    2020-09-11

  • 30 分钟轻松搞定正则表达式基础

    提起正则表达式,可能大家的第一印象是:既强大好用但也晦涩难懂。正则表达式在文本处理中相当重要,各大编程语言中均有支持(跟 Linux 三剑客结合更是神兵利器)。正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符

    2022-08-31

  • 30 分钟玩转「正则表达式」

    推荐阅读:Jeffrey Friedl 《精通正则表达式(第3版)》,本文是该书的读书笔记。

    2020-12-01

  • Prolog 基础

    Prolog 是种逻辑式的编程语言

    语言 & 开发 文化 & 方法 方法论 编程语言
  • Prolog 匹配

    讨论 Prolog 中的匹配, 解释匹配(match)与相等的不同.

    文化 & 方法 语言 & 开发 最佳实践
  • 拓展 1|纯文本编辑:使用 Vim 书写中英文文档

    今天是拓展篇的第 1 讲,我们深入讨论一下,如何使用 Vim 来进行纯文本编辑,特别是英文的文本编辑。

    2020-08-19

发现更多内容

架构师训练营-第1周学习总结(1期)

阿甘

UML

如何让知识图谱告诉你“故障根因”

华为云开发者联盟

华为云 知识图谱 图谱

用Go-Guardian写一个Golang的可扩展的身份认证

朱亚光

微服务 身份认证 Go 语言

Week 13 学习总结

Jeremy

面试常考算法题之 Top K 问题

小齐本齐

数据结构 算法

Netty之旅三:Netty服务端启动源码分析,一梭子带走!

一枝花算不算浪漫

Netty

服务质量分析:腾讯会议&腾讯云Elasticsearch玩出了怎样的新操作?

腾讯云大数据

大数据

读书笔记之《普罗普:故事形态学》

AI代笔

在Ubuntu 20.04 搭建 Django 开发环境 以及 快速构建一个简单的 Blog

Matrix Chan

Python django 后端 Ubuntu20.04

应对高并发系统有没有通用的解决方案呢?

架构师修行之路

架构 高并发 异步

架构师训练营 - 大作业

张明森

区块链合约层是一种自动执行的数字协议

CECBC

区块链 智能合约

两年Java开发经验赶上金九招聘季涨到23K,这究竟是怎么做到的?

Java架构师迁哥

Week 13 命题作业

Jeremy

架构师训练营-第1周课后作业(1期)

阿甘

架构师训练营第 0 期 期末大作业

无名氏

Clickhouse在大数据分析平台-留存分析上的应用

腾讯云大数据

大数据

Apache Pulsar 在腾讯 Angel PowerFL 联邦学习平台上的实践

Apache Pulsar

Apache 学习 开源 Apache Pulsar

Java面试史上最全的JAVA专业术语面试100问 (前1-50)

Java架构师迁哥

百度大脑6.0重磅升级 不断进阶中的中国AI底座实力尽显

脑极体

繁星计划将成为引领全球币值管理的带动计划!

InfoQ_967a83c6d0d7

彻底理解JavaScript执行上下文

Walker

Java 大前端 this指针 函数执行

USDT跑分承兑系统开发,区块链支付平台搭建

介绍

剑心

学习

哈哈,成为作者了

大海

@所有人 Flink Forward Asia 2020 向您发出议题征集邀请!

Apache Flink

flink

滴滴基于 Flink 的实时数仓建设实践

Apache Flink

flink

我写了一个TypeScript虚拟机。

渔子长

Java typescript 大前端 deno Node

LeetCode题解:206. 反转链表,双指针,JavaScript,详细注释

Lee Chen

大前端 LeetCode

金融企业敏捷转型大咖风采 | 中国出口信用保险公司的 DevOps 落地之道

Atlassian

项目管理 DevOps 敏捷 行业资讯 Atlassian

甲方日常 15

句子

工作 随笔杂谈 日常

刨根究底正则表达式之一:正则表达式概述_最佳实践_林耀平(笨笨阿林)_InfoQ精选文章

哆哆女性网理想照耀中国观后感800字十七岁的单车梦见买房子是什么意思 周公解梦港诡实录是真实事件吗鬼故事半夜鬼敲门四大名捕游戏为什么嘴巴周围容易长痘痘中日韩超长雨季原因面包店铺起名seo么永城天润城姓印男孩起名周易起名周易测周公解梦大全梦见头发白了秋季养生小常识圣牌珠宝朱姓男孩起名2020初学者如何做好网络营销推广吴亦凡被判刑了嘛隐形防盗窗价格鸡蛋灌饼名字起名大全抚州市网站制作李潇后面跟什么字起名网站优化推广做如何写好自己的签名造梦西游4破解下载盐城网站建设公司酒吧起什么名字好诗经论语史记唐诗宋词起名字杜受田淀粉肠小王子日销售额涨超10倍罗斯否认插足凯特王妃婚姻不负春光新的一天从800个哈欠开始有个姐真把千机伞做出来了国产伟哥去年销售近13亿充个话费竟沦为间接洗钱工具重庆警方辟谣“男子杀人焚尸”男子给前妻转账 现任妻子起诉要回春分繁花正当时呼北高速交通事故已致14人死亡杨洋拄拐现身医院月嫂回应掌掴婴儿是在赶虫子男孩疑遭霸凌 家长讨说法被踢出群因自嘲式简历走红的教授更新简介网友建议重庆地铁不准乘客携带菜筐清明节放假3天调休1天郑州一火锅店爆改成麻辣烫店19岁小伙救下5人后溺亡 多方发声两大学生合买彩票中奖一人不认账张家界的山上“长”满了韩国人?单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#青海通报栏杆断裂小学生跌落住进ICU代拍被何赛飞拿着魔杖追着打315晚会后胖东来又人满为患了当地回应沈阳致3死车祸车主疑毒驾武汉大学樱花即将进入盛花期张立群任西安交通大学校长为江西彩礼“减负”的“试婚人”网友洛杉矶偶遇贾玲倪萍分享减重40斤方法男孩8年未见母亲被告知被遗忘小米汽车超级工厂正式揭幕周杰伦一审败诉网易特朗普谈“凯特王妃P图照”考生莫言也上北大硕士复试名单了妈妈回应孩子在校撞护栏坠楼恒大被罚41.75亿到底怎么缴男子持台球杆殴打2名女店员被抓校方回应护栏损坏小学生课间坠楼外国人感慨凌晨的中国很安全火箭最近9战8胜1负王树国3次鞠躬告别西交大师生房客欠租失踪 房东直发愁萧美琴窜访捷克 外交部回应山西省委原副书记商黎光被逮捕阿根廷将发行1万与2万面值的纸币英国王室又一合照被质疑P图男子被猫抓伤后确诊“猫抓病”

哆哆女性网 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化