简单入门正则表达式 - 第一章 概述

来源:互联网 发布:两个矩阵卷积的定义 编辑:程序博客网 时间:2024/05/16 05:17
#content-region {background-image: url(http://p.blog.csdn.net/images/p_blog_csdn_net/rcom10002/EntryImages/20081027/watermark.gif);}#content-region h3 {border: 1px dotted #333333;background-color: #f9f9f9;padding: 10px;font-size: 24px;}#content-region p {font-family: "宋体", "仿宋";font-size: 16px;line-height: 28px;text-decoration: none;text-indent: 32px;}#content-region .regex-pattern {font-style: oblique;font-family: "Courier New", Courier, monospace;background-color: #FFCCCC;border-top-style: solid;border-right-style: none;border-bottom-style: solid;border-left-style: none;border-top-color: #FF0000;border-bottom-color: #FF0000;border-top-width: 1px;border-right-width: 1px;border-bottom-width: 1px;border-left-width: 1px;border-right-color: #FF0000;border-left-color: #FF0000;padding: 0px 5px 0px 5px;}#content-region .regex-result {font-family: "Courier New", Courier, monospace;background-color: #A4FFE1;border-top-style: solid;border-right-style: none;border-bottom-style: solid;border-left-style: none;border-top-color: #339966;border-bottom-color: #339966;border-top-width: 1px;border-right-width: 1px;border-bottom-width: 1px;border-left-width: 1px;border-right-color: #339966;border-left-color: #339966;padding: 0px 5px 0px 5px;}#content-region blockquote {padding: 10px;border-top-width: 1px;border-right-width: 1px;border-bottom-width: 1px;border-left-width: 1px;border-top-style: dotted;border-right-style: dotted;border-bottom-style: dotted;border-left-style: dotted;width: auto;}#content-region img {border: 1px dotted #000000;padding: 16px;background-color: #f9f9f9;margin-top: 16px;margin-right: 16px;margin-bottom: 16px;margin-left: 64px;}#content-region code {white-space: pre;}

一、正则表达式的诞生

最初的正规表达式出现于理论计算机科学的自动控制理论和形式语言理论中。在这些领域中有对计算(自动控制)的模型和对形式语言描述与分类的研究。1940年代,Warren McCulloch与Walter Pitts将神经系统中的神经元描述成小而简单的自动控制元。稍后,数学家Stephen Kleene利用称之为正则集合的数学符号来描述此模型。Ken Thompson将此符号系统引入编辑器QED,然后是Unix上的编辑器ed,并最终引入grep。自此,正规表达式被广泛地使用于各种Unix或者类似Unix的工具。自从那时起,正则表达式经过几个时期的发展,现在的标准已经被ISO(国际标准组织)批准和被Open Group组织认定。

正则表达式并非一门专用语言,但它可看作在一个文件或字符里查找和替代文本的一种标准。它具有两种标准:基本的正则表达式(BRE),扩展的正则表达式(ERE)。ERE包括BRE功能和另外其它的概念,关于两者之间的具体关系与区别,请参考网站 www.opengroup.org。 许多应用程序中都使用了正则表达式,包括xsh,egrep,sed,vi等等。并且在目前流行的编程语言中,如Java、.Net、PHP、Rubby 和 JavaScript等,正则表达式的身影也无处不在。

二、正则表达式引擎

了解正则表达式的引擎工作机制,有助于我们更加容易、准确地构造简单或复杂的正则表达式;更重要的是我们在构造正则表达式不用靠猜测或假象去完成它。正则表达式引擎分成两类,一类称为 DFA (确定性有穷自动机)引擎,另一类称为NFA(非确定性有穷自动机)引擎,有时它们也被称为文本导向(Text-Directed)引擎和正则导向(Regex-Directed)引擎。

文本导向的引擎是一个以线性时间顺序执行的确定性有限自动机,因为它们不需要backtracking,也正是因为这样,它们也从不会连续两次地匹配相同字符。文本导向引擎会尽可能地匹配最长的字符串。但是由于确定性有限自动机只能包含唯一的有限状态,它就不可能利用逆向引用来匹配一个样式;文本导向引擎也不能显示地构建一个扩展(expansion),从而也就无法捕获子表达式。

文本导向的引擎的特性如下:

  • 查找迅速
  • 查找时间与字符串长度相关
  • 比非确定性有限自动机消耗更多内存
  • 编译正则表达式时,需要更多的时间

正则导向的引擎是一个非确定性有限自动机,这种算法将会测试所有可能的匹配情况,并且每次只接受第一个匹配的内容。因为非确定性有限自动机(NFA)能成功地为正则表达式构建一个特定的扩展,从而也就能捕获子表达式(捕获组)的匹配内容和逆向引用所指向的内容。并且,NFA可以进行回溯操作,这样的话它也就能精确地多次访问同样的状态,即使这个状态已经处于一个不同的路径,所以,在一个非常糟糕的情况下,它运行起来是很慢的。

在使用正则导向引擎时有一点是非常值得注意的,它总是返回最左侧的匹配内容,即使是后面的内容可能是更好的匹配内容;但这并不代表它永远地抛弃剩下的匹配内容,在适当的情况下,回溯操作可能会把其他匹配内容给筛选出来。当我们把构造好的正则表达式应用到一个字符串上时,引擎就会从第一个字符开始。它将按照表达式中的顺序,把所有可能的内容都尝试一次,但每次的结果只是正则导向引擎执行该次匹配操作所能返回的最左侧的匹配内容。

正则导向的引擎的特性如下:

  • 查找较慢
  • 查找时间与正则表达式相关
  • 比DFA占用的内存少(具体占用内存多少与构造的正则表达式相关)
  • 编译速度比DFA要快(具体编译时间与构造的正则表达式相关)
  • 使用回溯算法来尝试所有可能的匹配内容
  • 不同的回溯风格直接影响性能
  • 能够捕获子表达式
  • 支持逆向引用

三、正则表达式的适用范围

正则表达式能够帮助我们方便快捷的进行文字处理,校验数据的合法性,辅助程序开发 ,简化开发过程。而且,很多程序语言对正则表达式也都有着不同程度上的支持,这就是使得我们所掌握的正则表达式知识的应用面更为广泛。但是,一定要注意的是,可能会因为语言或工具的不同,对同样的正则表达式语法有着不同的解释,这就需要我们使用这些语法之前仔细查阅相关文档;不过也不用过于紧张,这样的情况可能是因特定的语言或工具对它所支持的正则表达式进行了扩展等行为造成的,但我们所掌握的绝大多数正则表达式知识都是通用的。

四、正则表达式工具介绍

在我们编写正则表达式样式时,如何知道编写出来的正则表达式能跟我们预想的匹配模式一致,或者是能够满足我们所要进行的操作呢?这就需要我们借助一些辅助性工具,最简单的也是最朴素的工具就是我们经常使用的一些文本编辑器,如EditPlus、UltraEdit和EmEditor等。当然,如果您的要求比较高的话,也可以使用一些专业的正则工具,如 Expresso、RegexBuddy 等。

Expresso 是一款用 .Net 技术编写正则表达式工具,我们可以从它的官方网站 www.ultrapico.com 免费下载。Expresso 非常适合作为正则表达式初学者的学习工具,同样,它也适合作为有经验的程序员或网页设计者的一个辅助性开发环境。要安装并使用 Expresso ,首先要保证的是我们的机器上已经安装了适合版本的 Mircosoft .Net Framework,该框架可以从微软网站免费获取,Windows SP2、Windows 2003 SP1 和 Vista 都已经集成了 .Net 框架,不需要我们另外安装。

首次启动 Expresso 时,Expresso 会为我们提高它所提供的示例正则表达式,如下图所示。从图中的选项卡来看,Expresso 为我们大致提供了字符串匹配、字符串替换、常用正在表达式类库、最近使用的正则表达式、正则表达式分析和正则表达式模式设定几个功能。当我们点击右边的按钮时,我们就能看到相应功能的运行结果,关于 Expresso 的详细用法我们会将在以后章节的示例中学到。

Expresso截图

目前流行的正则表达式工具种类有很多,如 Regex Coach、Regular Expression Designer等,并且还有一些提供正则表达式测试的网站,如 www.regextester.com 等,我们可以根据自己需求,选择合适的测试工具。

五、正则表达式不擅长的事情

正则表达式的主要作用的用于匹配某一种样式的字符或字符串,它本身并不具有逻辑校验功能。为什么要在这里提出这个话题呢,因为在国内一些大型的程序论坛中,经常有人问如何用正则表达式判断日期有效性这样含有复杂逻辑的问题。如果单纯地使用正则表达式验证日期的格式,如 YYYY/MM/DD 这样的形式,当然是很轻松就能做到的,但是,对于2月份不能出现31号这样的逻辑问题,用正则来实现有些勉为其难了,有些情况下甚至是无法实现或是实现了也是相当复杂的。

曾经看到一个验证日期有效性的正则表达式表达式:

(([0-9]{2}([02468][048])|([13579][26])))(02)(([0][1-9])|([1-2][0-9]))|(([0-9]{2}([02468][123579])|([13579][01345789])))(02)(([0][1-9])|([1][0-9])|([2][0-8]))|([0-9]{4})(([0](1|3|5|7|8))|10|12)(([0][1-9])|([1-2][0-9])|30|31)|([0-9]{4})(04|06|09|11)(([0][1-9])|([1-2][0-9])|30)

这样的写法如果是用在教学中,确实是一个不可多得的好例子,但要用在实际开发中,就不太合适了。首先,任何人看了这样长的一个正则表达式,心里想的第一个问题就是该如何看懂它——太复杂!其次,在编写它的时候,逻辑思路必须特别特别清晰,因为稍微一个不留神,就可能遗漏某个环节——难编写!第三,正则表达式在使用之前都是需要编译的,语法越复杂编译起来也就越慢,而且执行起来也不见得会比我们普通编写的程序代码跑得快——效率低!

所以,一定要记住,正则表达式的优势是进行样式匹配,而不是具体的逻辑处理。只有正确地认识到这一点,在程序编写时合理地使用正则表达式,才能明确问题的关键所在,得出一个最佳的解决方案。

六、关于正则表达式学习的几点建议

工欲善其事,必先利其器!所以,一个良好的正则学习工具是非常有必要的。这样不光能加快学习进程,还能有效地巩固我们学习过的知识。像我们在上面已经介绍过的 Expresso 这样正则表达式测试工具,对我们的学习都能起到很大的帮助作用。这些工具大多都能帮助我们创建、编辑正则表达式;并能对匹配的内容高亮显示、进行语法分析。另外,有的工具还附带常用的正则表达式校验类库、自动生成代码等功能。

在我们的学习过程中,最好是能把编写的正则表达式拿到程序代码里实际的跑一下,这会加深我们的理解。在很多程序语言中实现了字符串对正则的支持,如 Java 包 java.lang 中的 String 类就提供了 matches、replaceAll、replaceFirst、split 四个方法; 另外一种就是利用正则表达式类所提供的静态方法,如 .Net 命名空间 System.Text.RegularExpressions 中的 Regex 类就提供了 IsMatch、Replace 和 Split三个静态方法。总的来说,无论是字符串提供的普通方法,还是由正则表达式类所提供的静态方法,它们都是匹配、替换和分割三种操作。通过这样的学习方式,不光能够牢牢地掌握正则表达式语法,还能熟悉日常工作学习时所使用的常用正则表达式方法,一举两得,不用花费额外的时间来补习程序语言上的正则表达式知识了。

原创粉丝点击