正则表达式笔记

来源:互联网 发布:手机开启数据 没有网络 编辑:程序博客网 时间:2024/05/18 00:11

打算系统的学习下正则表达式,该文为笔记及学习体会。

什么是正则表达式

正则表达式是用来描述字符组合规则的,例如邮编是6个数字组成的,用正则表表达式就是【\d\d\d\d\d\d】,【\d】可以匹配0-9这10个数字中的任意一个。

【\d】在正则表达式中被称为元字符,元字符指的是在正则表达式中具有特定用处的一组字符,它是正则表达式的基础,以下课程中我们将通过实例为您逐一介绍。

正则表达式学习工具

要学好正则表达式,必要要多动手、多思考,因此准备一款简单易用的学习工具就很有必要,我们为您推荐RegExr,它是一款免费在线正则表达式学习工具,具有实时高亮显示、语法提示、免安装的特点。如果您有需要也可以选择下载安装它的桌面版。RegExr由Flash的ActionScript3.0脚本开发,它只支持ActionScript3.0中的正则语法。但这并不影响我们的学习,正则表达式具有良好的兼容性。在javascript、AS3.0、vb、vc、java等环境中,95%以上的元字符都是一样的。

RegExr在线版网址:http://www.gskinner.com/RegExr/
RegExr桌面版下载:http://www.gskinner.com/RegExr/desktop/
RegExr桌面版安装:setupRegText.htm

教材介绍

本教材是按照元字符的功能分类介绍的,元字符按功能可以分为以下几类:

  1. 匹配字符本身:如匹配数字的\d,匹配空格的\s。
  2. 匹配字符数量:如匹配一个由3个数字组成的字符串,就可以用\d{3},其中{3}就是匹配数量的。
  3. 匹配字符位置:如匹配字符串开始处就使用^,^an就只会匹配字符串开始处的an,而不会是字符串中间an。
  4. 分组匹配:使用圆括号可以一次匹配多个元素,如(ab){3}就可以匹配ababab。
  5. 正则表达式选项:选项不会直接参与正则匹配运算,但它会改变匹配中的行为,如忽略大小写、全局匹配等等。

匹配字符的元字符

概述

正则表达式的元字符中,有一部分是直接可以匹配某一个具体的字符,例如匹配空格的\s,匹配数字的\d,有时我们想同时匹配1、2、4这3个数字中的任意一个我们可以使用方括号的形式[124],匹配汉字我们必需使用\uxxxx的形式xxxx代表的是汉字的unicode编码。

匹配任意字符(除了换行符)

【.】匹配除了换行符以外的任意一个字符。要匹配【.】本身,请使用转义符【\.】。使用【.】的时候,大家必需要了解换行符在不同的系统中有不同的表示方法,windows下是【\r\n】,ActionScript中是【\r】而JavaScript中是【\n】。

实例说明匹配结果举例 a..b匹配以a字母开头,以b字母结尾,中间是两个除了换行符以外的任意字符。 "a12b"、"aoob"、"ao_b"、"aceb"、"a-sb" 12\.33【\.】是匹配【.】本身 。12.33 

匹配单词字符和非单词字符

元字符[\w]单词字符通常指的是字母、数字、下划线。此元字符中的w大写和小写的意思完全相反,大家在使用过程中一定要注意。类似这种一个大写一个小写形式的元字符还有两种,它们分别是匹配数字的【\d】和匹配非数字的【\D】、匹配空格的【\s】和匹配非空格的【\S】。

实例说明匹配结果举例 g\w\wd匹配以g字母开头,以d字母结尾,中间是两个单词字符。 "good"、"gkkd" g\W\Wd匹配以g字母开头,以d字母结尾,中间是两个非单词字符。 "g~!d"、"g--d"

匹配数字和非数字

数字字符指的是0到9这10个字符。【\D】匹配除了数字字符以外的所有字符,也包括换行符。

实例说明匹配结果举例 g\d\dd匹配以g字母开头,以d字母结尾,中间是两个数字字符。 "g12d"、"g33d"g\D\D\Ds匹配以g字母开头,中间是3个非数字字符,以s字符结尾的字符串。"g,,-s"、"g-s-s"

匹配空格和非空格

匹配空格字符使用【\s】,匹配非空格字符使用【\S】。

实例说明匹配结果举例 g\s\sd匹配以g字母开头,以d字母结尾,中间是两个空格的字符串。 "g  d" g\S\Sd匹配以g字母开头,以d字母结尾,中间是两个非空格字符的字符串。"good"、"g12d"、"g-3d"

匹配换行符和回车符

换行符和回车符在不同的系统环境中使用的方式有所不同,这里我们把它们放到一起来学习。【\r】被称为换行符,而【\n】是回车符,但是具体的某个应用环境中,真正起到换行作用的有可能是【\r】(如ActionScript 3.0),也有可能是【\n】(如JavaScript和unix),也有可能是【\n\r】(如dos),也有可能是【\r\n】(如windows内核)。它们之所以这么多的不同区别,那是有着历史原因的,想了解更多内容可以查看《换行符和回车符的历史》。

下面我们举例说明,看看它们具体是怎样进行匹配的。大家请先打开RegExr,在表示式一栏中输入【.+】,【+】表示【.】重复了一次或任意多次,内容一栏中输入随意输入两行字符。如下图所示(注意,一定要把global选项取消,它是全局匹配的意思,在之后的表达式选项一课中我们将会介绍到它)。

 hh3img.jpg

通过测试我们发现【.+】只匹配了第一行内容,因为【.】是不能匹配换行符的,所以到行尾匹配就结束了。想同时也匹配下一行,只需要把表示示改为【.+\r.+】。【\r】匹配行尾的换行符。结果见下图:

 hhimg.jpg

以上的实例都是在AS3.0的环境中用法,如果是在JavaScript中需要把【.+\r.+】改成【.+\n.+】。 

匹配汉字和其他亚洲字符

在正则表达式中匹配汉字通常使用的是【\uxxxx】的形式,xxxx代表的是汉字的unicode编码,如汉字“中”的unicode编码是" 4e2d ”,那么正则表达式中匹配“中”字就要使用【\u4e2d】,要匹配韩文日文都可以使用这种方式,您只需要查找到这些字符所对应的unicode编码就行了。(由于RegExr对这个功能的支持有bug,在下面我们为您另外提供了一个测试工具以及unicode编码查询工具。)

unicode编码查询工具:cntounicode
汉字匹配测试工具:hzpptool

实例说明匹配结果举例\u6b63\u5219\u8868\u8fbe\u5f0f6b63、5219、8868、8fbe、5f0f分别是汉字“正则表达式”的unicode编码"正则表达式" \u304a\u65e9\u3046匹配日文 "お早う""お早う"

按字符组匹配

之前的课程中我们知道【\d】可以匹配0-9,但有时只想匹配5,6,7,8这4个数字,这时可以使用方括号将要匹配的字符都列举出来如【[5678]】,方括号取了可以列举数字外,也可以列举字母如【[abc]】,如果列举出来的元素是连续的,也可以简写为【[a-d]】或【[5-9]】的形式,它还可以通过加上【^】符号实现反向匹配,如【[^abc]】匹配除了a、b、c这三个字符以外的所有字符。 

方括号的使用的方式是灵活多变的,通过下表中的实例学习,相信大家很快就可以掌握。

实例说明匹配结果举例[abc]123匹配以"a"或"b"或"c"开头并以"123"结尾的字符串。 "a123"、"b123"、"c123"[d-g]123 匹配以"d"或"e"或"f"或"g"开头并以"123"结尾的字符串。 "d123"、"e123"、"f123"、"g123"[^2-5]\d\d\d匹配除了 2,3,4,5 以外的所有字符,后面是任意3个数字组成的字符串。"a123"、"6123"、"-123"、"(123"[a-c2-3]good匹配以"a"或"b"或"c"或"2"或"3"开头以"good"结尾的字符串。"agood"、"bgood"、"3good"、"2good"[^a-c2-3]匹配除了"a"、"b"、"c"、"2"、"3"以外的所有字符。"d"、"o"、"-"、"@"[\da-c]匹配0-9这10个数字,以及a、b、c这三个字符。"1"、"2"、"a"、"b"

其它杂项

此部分匹配字符的元字符并不常用,这里给大家一次性的列举出来,如有需要的时候,可以回过头来查询。

元字符说明\0匹配null空字符 \t匹配制表符\f匹配分页符\v匹配垂直制表符\xxx匹配以八字制xxx规定的字符\xdd匹配以十六进制dd规定的字符

练习题

  1. 元字符【.】匹配什么内容,它不能匹配的字符是什么?
  2. 什么是单词字符,匹配单词字符,我们该使用什么元字符?
  3. 有那三种元字符同时有小写和大写形式,大写后的匹配效果是什么?
  4. 怎样匹配汉字以及其他的亚洲字符?
  5. 如果我们只想匹配文本中的3,4,8这三个数字正则表达式该怎么写?
  6. 列举3种正则表达式元字符方括号的使用方法。

匹配字符数量

概述

匹配数量的这类元字符不可以单独使用,它们通常用来描述它前一个或一组元素重复的次数。如【d{3}】匹配"ddd",而【ad*】匹配"a"、"add"、"addd"其中d可以重复零次或任意次数。【(ad){3}】匹配"ababab",圆括号起到一个分组的作用,在分组一节中我们会详细介绍。描述数量的元字符有4种形式,分别是:

  • 【*】匹配前一个元素或一组元素重复零次任意次
  • 【+】匹配前一个元素或一组元素重复一次任意次
  • 【?】匹配前一个元素或一组元素重复零次
  • 【{n,m}】匹配前一个元素最少重复n次最多重复m次

前三种形式基本相同,我们通过下表中的实例可以很快就掌握,第四种形式稍微复杂一点点,稍后会单独介绍,学习过程中大家一点要记得多动手实验噢。

实例说明匹配结果举例abc*匹配以ab字符开头后有零个c或任意多个c的字符串。 "a"、"acc"、"acccccccc"a(bc)+匹配以"a"字符开头后面有一个或任意恟个"bc"字符的字符串 "abcbc"、"abc"、"abcbcbcbcbc"ao?匹配以"a"字符开头后面有零个或一个"o"字符的字符串。"a"、"ao"

使用花括号匹配元素重复次数

花括号通过设定最大匹配次数和最小匹配次数可以精确的指定前一个或一组元素重复的次数,匹配花括号本身请使用转义符【\{】和【\}】。它有3种使用方法:

  • {n}匹配时元素需要重复n次。
  • {n,m}匹配时元素最少要重复n次,最多只能重复m次。{0,1}相当于【?】的作用。
  • {n,}匹配时元素最少要重复n次,最多可以重复任意次。{0,n}相当于【*】的作用,{1,n}相当于【+】的作用。

实例说明匹配结果举例\d{3}相当于\d\d\d。 "123"、"111"、"599"\d{2,5}相当于\d\d、\d\d\d、\d\d\d\d、\d\d\d\d\d "12"、"123"、"12345"(ab){3,}匹配时"ab"要重复最少3次,最多任意次。"ababab"、"abababababab"

 

非贪婪匹配

在使用数词进行匹配的时候,表达式会尽可能多的匹配符合条件的元素,例如用ab+匹配abbbbbbb时,它不会匹配ab,也不会匹配abbbb,只会匹配abbbbbbb。这样的匹配方式被称为“贪婪匹配”。但有时我们不想要数词匹配过多的内容,例如使用【<div>.+</div>】来匹配"<div>test1</div><div>test2</div>"中的 "<div>test1</div>" 和 "<div>test2</div>" 时就会出现问题,见下图

 tlyesimg.jpg

如图所示,表达式【<div>.+</div>】会把整个字符串一次性的都匹配了,但这是不对的。解决办法之一就是在把表达式中的加号元字符【+】后面加上个问号【+?】,结果如下图。

tlnoimg.jpg

 

类似于【+?】在正则表达式的数词后面加上问号的这种形式被称为“非贪婪匹配”,也就是数量词会尽可能少的去匹配符合条件的内容。例如上面的实例中【<div>.+</div>】可以匹配字符串"<div>test1</div><div>test2</div>","<div>test1</div>" 和 "<div>test2</div>"虽然都是符合匹配条件的,但它只会匹配内容最多的的那一个。而非贪婪模式下的【<div>.+?</div>】会匹配内容最少的那一个。

之前提到的四种表示数量的元字符【*】【?】【+】【{n,m}】都可以通过加上问号实现“非贪婪匹配”。详情见下表:

实例说明匹配结果举例ba*?匹配以b字母开头,后面有零个或多个a(取最少的a,那么也就是0个)只能匹配b,而不能匹配baba??匹配以b字母开头,后面有1个或多个a(取最少的a,那么也就是1个)只能匹配ba,而不能匹配baaaaba+?匹配以b字母开头,后面有0个或1个a(取最少的a,那么也就是0个)只能匹配b,而不能匹配baba{3,4}?匹配以b字母开头,后面有3个到4个a(取最少的a,那么也就是3个)只能匹配baaa,而不能匹配baaaa

练习题

  1. 匹配数量的元字符有那几种?
  2. 如果有一个我想匹配一个由3个数字组成的字符串,表达式该怎么写?
  3. 如果我们想匹配一个网址,所有网址都包括了www,在www前面有可能有"http:"也有可能没有"http:"这个字符串,正则表达式该怎么写?
  4. 什么是非贪婪匹配,它的书写形式是怎样的?

匹配字符位置

概述

有时在进行匹配的过程中,我们会要求某一字符必需位于字符串的起始处,或位于单词的起始处和结束处,这时就需要使用【^】【$】【\b】这种元字符。【^】匹配字符串的起始处或行的起始处,【$】匹配字符串的结束处或行的结束处,【\b】匹配单词的分界处。【^】是匹配字符串的起始处还是行的起始处和正则表达式的m选项有关。【$】和【^】一样,匹配效果与m选项有关系。关于m选项的详细内容我们将在后面的“正则表达式选项”一课中学习。

匹配字符串的起始处和结尾处

 【$】和【^】在没有打开m选项的时候,它们分别匹配字符串的起始处和结尾处。所谓的字符串是不管内容中有多少行的,就是有100行的内容,系统也只会把它看做是一个字符串。例如下图中的实例中内容一栏中有3行同样的字符,正则表达式为【morning$】它只会匹配最后一个morning字符。而图2中的正则表达式为【^good】它只会匹配字符串中的第一个good字符。

stringendimg.jpg

 

stringbegimg.jpg

匹配行的起始处和结尾处

【$】和【^】在开m选项的时候,它们分别匹配行的起始处和结尾处,m选项位于下图中的红框部分,正则表达式不变,大家可以亲手比较一下选择了m选项和不选择m选项的不同。

stringbegimg2.jpg

 

stringendimg2.jpg

通过亲手测试我相信大家很容易就区分出它们的异同之处了。

匹配单词的边界处

【\b】可以匹配单词的边界处,这里的单词指的是字母、数字、下划线组成的连续的字符串,也就由一个或多个【\w】组成的连续的字符串。"ab_c"、"ab_01"、"11aa"他们都可以被看作是一个单词。知道了计算机中单词的定义后,我们看个实例,见下图。在"an banana"这个字符串中使用【an】可以匹配3个"an"(第一张图),但使用【\ban\b】的话就只会匹配单词"an"(第二张图)。

danchiimg.jpg

 

danchiimg2.jpg

练习题

  1. 匹配位置的元字符有那几种?
  2. m选项对那两种元字符匹配结果有影响?影响的结果是什么? 

分组匹配

概述

通常情况下,ab{3}这类使用了数量词的正则表达式,数量词只会处理前一个元素,例如【ab{3}】中的数量词【{3}】只会处理b而不是ab。除非我们改写为【(ab){3}】,其中的圆括号就是分组符号。在正则表达式中分组操作可以实现很多功能,除子让ab做为一个整体运算外,还可以将匹配的内容存储起来进行后续的去处,还有先行断言的功能等等。是不是感觉挺复杂的,其实没关系,我们只要安下心来一个功能一个功能的学习,学会了以后就很简单了。

分组的功能主要可以分为以下3种:

  1. 把元字符进行组合,然后统一处理,(abc){3}就属于这种形式
  2. 将匹配结果进行捕获同时分配一个组号,之后可以进行反向调用。
  3. 进行先行断言处理,也就是在匹配前确定被匹配的内容的左边和右边,可以或不可包括某些字符。

用圆括号组合元字符

圆括号可以将几个元字符组合成一组,那么这时使用数词元字符的话,数词会一次性处理这一组元素,如 " (http://)?www ",就可以匹配 " http://www和www ";它还可以进行多层嵌套,如((abc)\w{3});在括号中还可以用一条竖线表示或的意思同时匹配多个元素,如((good)|(best))可以匹配字符串"best"或者是"good"。

实例说明匹配结果举例(http://)?www(http://)?匹配零个或一个"http://"这个字符串。"www"、"http://www"((abc)\w{3})此实例中嵌套了2个圆括号,分别是(abc)和 ((abc)\w{3})"abcooo"、"abc1_2"、"abco12"((good)|(best))此实例中good与best中间有个竖线进行“或”运行,所以它可以匹配"best"也可以匹配"good""best"、"good"

捕获分组内容并进行反向引用

在很多应用环境中都可以将圆括号中匹配的内容存储到内存中同时分配一个组号,之后我们可以调用组号进行引用。例如正则表达式【(\d{3})([a-z]{3})】第一个圆括号匹配3个数字组成的字符串,如"111",它会被分配一个组号$1;第二个圆括号匹配3个字母组成的字符串,如"aaa",它会被分配一个组号$2。下面我们通过实例来一步步的解释在真实环境下,是怎样去实现反向引用的。

首先打开RegExr测试工具,选择replace选卡(图中的第一个红框),然后在剩下的三个红框位置按图中内容依次录入。这时查看一下结果,是不是发现111和aaa被调换了前后的顺序。这是因为我们在替换框中使用了$2$1。$2这个组号属于【([a-z]+)】,而$1属于【(\d+)】。看到这里我想大家就应该很清楚组号的作用了吧。此功能在apache重写模板和各种编程工具replace函数中都有应用。

fezuimg.jpg

非捕获匹配

通过前面的课程学习,我们知道,在使用圆括号进行分组匹配时,系统会存储圆括号匹配的内容,并分配组号,这种操作会占用一定的系统资源,影响正则表达式的执行效率,如果我们已经确定将来不会引用分组中的内容,那么也就无须让它保存在内存中。此时只需在圆括号中加上【?:】就行了,例如【(?:\b\w+\b)】。大家也可以通过下图的实例加深理解。

nobh.jpg

实例中系统只捕获了表达式中第一个分组中的内容,同时分配了组号$1。而第二组没有进行捕获,也没有分组号,最终替换的结果也只是把 " $2 " 这个字符给显示了出来。

先行断言

先行断言,看着名字大多数人会感觉比较难以理解,实际上它的作用很简单,就是匹配时,被匹配的字符左边或右边必需包括或不包括一个字符串。如下图中的实例:

xxdy.jpg

实例中的【(?<=name:)】表示匹配的内容的左边必需包括"name:"这个字符串。它在正则表达式中被称为“ 零宽正向后行断言”。先行断言总共有四总,见下表:

名称作用语法零宽正向先行断言匹配内容的右边必需包括pattern匹配的内容。表达式(?=pattern)零宽负向先行断言匹配内容的右边不能包括pattern匹配的内容。 表达式(?!pattern)零宽正向后行断言匹配内容的左边必需包括pattern匹配的内容。(?<=pattern)表达式零宽负向后行断言匹配内容的左边不能包括pattern匹配的内容。(?!=pattern)表达式

练习题

  1. 【(an){3}】这个正则表达式中的圆括号的有什么作用?
  2. 【( \d | [a-z] )*】圆括号中的竖线有什么作用?这个正则表达式匹配什么内容?
  3. 圆括号分组匹配时是否会分配组号?组号有什么作用,请通过实例说明。
  4. 非捕获匹配有什么作用,它的书写形式是什么样的?
  5. 先行断言有那几种,它们的写法分别是什么?

正则表达式选项

概述

正则表达式主要是用于改变元字符的匹配效果,常用的正则表达式选项有三种,分别是全局匹配(goable)、多行模式(multiline)、忽略大小写(ignoreCase)。

全局匹配选项

通常在进行正则表达式匹配时,全局匹配选项(g)都是打开状态,如果没有打开,匹配运算只会匹配第一个满足条件的字符串,例如表达式【a】在匹配字符串"banana"的时候,默认全局匹配选项(g)打开的情况下"banana"中的3个a都可以匹配,但在取消了g选项以后,【a】就只会匹配第一个a。匹配效果见下图:

gopt.jpg

nogopt.jpg

多行模式

多行模式选项(m)之前我们在讲到元字符【^】和【$】有介绍过,m选项会让【^】由匹配字符串起始处变为匹配行的起始处,让【$】由匹配字符串的结尾处变为匹配行的结尾处。

yesmul.jpg

nomul.jpg 

忽略大小写

正则表达式在匹配运算时,会匹配大小写,例如【a】只匹配小写的"a",而不会匹配大写的"A"。但使用了忽略大小写选项(ignoreCase)后,【a】可以匹配"a"和"A",【A】也同样可以匹配"a"和"A"。实例见下图: 

 

练习题

  1. 请分别说明正则表达式中 g 选项、m 选项、i 选项的作用?

学习总结

正则表达工的基础课程到这里已经全部完成,通过学习,相信大家对正则表达式的使用已经有了一个基本的掌握,要想在工作中能熟练的使用好这一强大的工具,大家必需多做、多想,有不明白的地方可以在网上查询,建议大家使用百度的问问,通常都会有很多热心人来帮助各位解决问题的,当然过后不要忘了感谢别人的帮助噢。

此课程讲解的都是一些正则表达式的基础知识,正则表达式做为一种字符处理工具,要用好他,必需对所要匹配的内容有个清楚的认识,例如你想匹配电子邮箱地址就一定要知道,电子邮箱由那几部分组成,在实际应用都有那几种形式,再比如你想匹配电话号码,就应该首先了解电话号码是由(+86)(0730)8288000 国家码+区号+电话号码 三个部分组成的。

最后还有关于正则表达式运行效率问题,之前我们在讲到非捕获匹配的时候就提过了,为了提高表达式的匹配效率,最好是使用非捕获组。为了提高表达式的匹配效率,我们总结以下几点,请大家一点要记住:

  1. 匹配范围要尽可能的小和精确,如匹配数字我们就只使用【\d】,而不使用【\w】。匹配2,3,4我们就使用【[234]】,而不使用【\d】
  2. 尽量少用分组符号圆括号。匹配"abc"字符串,我们就只使用【abc】,而不要使用【(abc)】虽然可读性好一些,但程序运行很多情况下追求的是效率,因为程序是给用户使用的,而不是程序员。
  3. 非贪婪式.+?计算代价比贪婪式的.+高。如果知道具体的限制大小,用{x,y}效率会更高。
  4. 没有特定需要请使用非捕获组。

总的来说就是运算的过程越短,匹配的效率就越高。


原创粉丝点击