一. 正则表达式的基础知识:
1.字符串的组成
对于字符串”123“而言,包括三个字符四个位置。如下图所示:
2.占有字符和零宽度
正则表达式匹配过程中,如果子表达式匹配到东西,而并非是一个位置,并最终保存到匹配的结果当中。这样的就称为占有字符,而只匹配一个位置,或者是匹配的内容并不保存到匹配结果中,这种就称作零宽度,后续会讲到的零宽度断言等。占有字符是互斥的,零宽度是非互斥的。也就是一个字符,同一时间只能由一个子表达式匹配,而一个位置,却可以同时由多个零宽度的子表达式匹配。
3.控制权和传动
正则表达式由左到右依次进行匹配,通常情况下是由一个表达式取得控制权,从字符串的的某个位置进行匹配,一个子表达式开始尝试匹配的位置,是从前一子表达匹配成功的结束位置开始的(例如:(表达式一)(表达式二)意思就是表达式一匹配完成后才能匹配表达式二,而匹配表达式二的位置是从表达式一的位置匹配结束后的位置开始)。如果表达式一是零宽度,那表达式一匹配完成后,表达式二匹配的位置还是原来表达式以匹配的位置。也就是说它匹配开始和结束的位置是同一个。
举一个简单的例子进行说明:正则表达式:123
源数据:123
讲解:首先正则表达式是从最左侧开始进行匹配,也就是位置0处进行匹配,首先得到控制权的是正则表达式中的“1”,而不是源数据中的“1”,匹配源数据中的“1”,匹配成功,将源数据的“1”进行保存到匹配的结果当中,这就表明它占有了一个字符,接下来就将控制权传给正则表达式中的“2”,匹配的位置变成了位置1,匹配源数据中的“2”,匹配成功,将控制权又传动给了正则表达式的“3”,这时候匹配的位置变成了位置2,这时候就会将源数据中的“3”进行匹配。又有正则表达式“3”进行传动控制权,发现已经到了正则表达式的末尾,正则表达式结束。
二、元字符
三、转义字符
如果你想要得到元字符本身的话需要使用“\”来取消这些元字符的特殊意义。
四、字符类
首先字符类使用“[]”包起来的,例如以下这个例子:(大小写要区分)
①[aeiou]则表示匹配任意一个英文元音字母(这个仅仅是匹配一个,也就是说你如果匹配了a这个整个正则表达式就已经结束了,这里面的逻辑表示的是“或”的意思),再看这个例子[.!?]表示匹配.或者?或者!
②[a-zA-Z0-9]这个正则表达式表示的是匹配a到z的任意一个小写字母,或者是A到Z的任意一个字母,或者是数字0到9任意一个.
五.重复(MSDN上称作是限定符)
六.分支条件
其实正则表达式中的分支条件,就指的是有几种规则:用“|”把不同的规则分开
来看下例子:
①0\d{2}-\d{8}|0\d{3}-\d{7}:匹配两种以连字号分隔的电话号码;一种是三位区号8位本地号(例如:010-12345678),另外一种规则则是4位区号7位本地号(例 如:0315-8834524)
②\d{5}-\d{4}|\d{5}:需要注意的是使用分支条件是一定要注意分支条件的顺序,如果改成\d{5}|\d{5}-\d{4}这个样子的话,那么只会匹配五位数字而不会匹配后面的四位数字(例如:我们利用第二个匹配12345-1234,它只会匹配12345,原因是:正则表达式是从左到右依次匹配,如果满足了某个分支的话它就不会再管其他分支了)
七.分组
你可以使用小括号()来指定字表达式:(\d{1,3}){3}\d{3}:这个正则表达式的意思就是把我们分组的小括号里面的东西重复三次,也就是说我们至少匹配3个最多匹配9个数字,后面再加上三个数字。
八.反义字符
九.反向引用
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。但是其实分组号不是这么简单:
•分组0对应整个正则表达式
•实际上组号分配过程是要从左向右扫描两遍的:第一遍只给未命名组分配,第二遍只给命名组分配--因此所有命名组的组号都大于未命名的组号
•你可以使用(?:exp)这样的语法来剥夺一个分组对组号分配的参与权.
通过上面三条讲述我们可以清楚地知道分组的方式是怎样的,其实意思就是首先我们先对没有为组进行命名的组进行分配组号(从左到右依次次分配),然后再对分配组号的组进行分配组号(使用(?<组名>)方式显示分配组名称),如果你想剥夺某一个组的组号可以采用(?:exp)这种方式进行剥夺,也就是不给他分配组号,可以理解为跳过此组。
正则表达式:(?3)(1)(2)(?565)
匹配文本:312565
匹配结果表明首先0号组的是匹配的整个表达式,匹配1号组名的则是1,匹配2号组的是2,匹配3号组的就是命名为work组名的3,匹配4号组的则是匹配命名为SmallDing组名的565,显然可以看到分配组号就是按照以上的规则来分配。
说到了反向引用我们来看一下反向引用是什么概念,我们前面已经详细讲解了组号的分配,那么反向引用则用于重复搜索前面某个分组匹配的文本,例如\1代表分组1匹配的文本
请看下面的例子:
正则表达式:(1)(2)(3)\2则表示匹配123且在此匹配组号为2的内容也就是再次匹配2
匹配文本:1232
正则表达式:(?333)(?222)(?:\d{3})该正则表达式代表的是显示为匹配333的组分配组名为work,显示为匹配222结果的组分配组名为222,但是如果匹配3位数字这个组已经取消了组号,所以该组号是没有的,也就是整个正则表达式是第一个组号为0,首先将所有未命名的组进行分配组号,而只有一个(?:\d{3})这个没有分配组名,但是它却将组号进行取消了,所以组号不会给它分配。
源文本为:333222123
那现在我们就来讲一下零宽断言和负零宽断言
常见的几种分组方法
零宽度断言
1.(?=exp):也叫零宽度正预测先行断言,它匹配自身出现的位置后面能匹配表达式exp
例如:\b\w+(?=ing\b)则这个正则表达式就是匹配一ing结尾的单词,但是不包含ing,这个零宽度正预测先行断言可以这样理解,我们就以上面的正则表达式作为例来进行讲解,首先我们肯定是匹配源文本为doing它会先匹配d的时候它会瞻仰一下后面跟的是不是ing,如果不是就会继续往下走,匹配到第二个字符o它会预测(或瞻仰)下后面是不是ing如果是整个表达式就结束了,并且不匹配ing。而这个可以总结一句话就是匹配exp前面的东西
2.(?<=exp):也叫零宽度正回顾断言,它匹配自身出现位置的前面匹配表达式exp,这句话听着很绕口,其实零宽度正回顾断言中解释说是自身出现位置这个自身出现位置是表示它匹配的文本,就比如说(?<=Ding)\d{3}这个正则表达式,这里的自身出现的位置仅仅是从开始匹配文本的时候也就是\d{3}也就是主动权在这个\d{3}的时候才是自身匹配的位置。举例说明源文本,比如匹配Din123,按照我们的常理理解的是数字123是自身匹配的位置,但是前面不是Ding所以匹配不成功,我们可以讲这个表达式理解为就是以exp为开始的正则表达式但是不包含exp,意思就是匹配exp后面的东西。
负向零宽断言:(可以和上面的进行对比来学哦!这个表达式的是否定的)
1.(?!exp):也叫零宽度负预测先行断言,断言此位置的后面跟的不能匹配表达式exp,
例如:\d{3}(?!123):正则表达式的含义表达了前面匹配的是三个数字,匹配的位置就是当前匹配的这三个数字后面跟的不能是123。
十.平衡组
接下来我来讲一下平衡租的原理,在上面我们做下了铺垫,也就是说我们在第六节的时候提出来了一系列问题,是不是感觉一头雾水,没关系的,到了这一节终于守得云开见月明了,听过本章节的学习我相信你们会对上面的问题进行一个详细合理的回答!OK,Come On Baby!懂你们迫不及待心情,一定会说你咋这多废话呢,好,闲话少说,继续....
说到平衡组有些人就会想到分组,没错他们之间是有联系的,也就是我们前面所讲的分配组号的问题,那下面呢我们先引出语法,详细见下表
十一、贪婪与非贪婪
首先先说一下关于贪婪匹配和非贪婪匹配的一些基本概念,贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。
下面是一些限定符(限定符指定在输入字符串中必须存在上一个元素(可以是字符、组或字符类)的多少个实例才能出现匹配项)
贪婪匹配的限定符如下表所示:
非贪婪是在贪婪限定符后面多加一个“?”,如下表所示:
十二、贪婪匹配和非贪婪匹配原理
其实这节贪婪匹配与懒惰匹配应该放在重复后面讲,因为这个和重复有关系,那么下面详细介绍什么是贪婪匹配什么是非贪婪匹配,贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为,贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配,而非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。非贪婪模式只被部分NFA引擎所支持。
(1).贪婪
来看一下匹配过程。首先将控制权交给“"”,由它来匹配第一个字符"匹配成功,将控制权转交给“.*”,这时候控制权掌握在了“.*”的手上,由于“*”是优先词量,在可匹配与不可匹配的情况下,优先尝试匹配,他就会尝试匹配第一字符R,匹配成功就会继续往下匹配,匹配第二字符e,匹配成功,继续向右匹配,直到匹配到结尾的“"”,匹配成功,再向后匹配时发现已经到结尾了,“.*”结束匹配将控制权转交给""","""发现已经到了源字符串的结尾,看有没有可供回溯的状态,将控制权给了“.*”,“.*”还回一个字符“x”,然后将控制权转交给“"”,来匹配后面的字符“"”,匹配成功正则表达式结束。这句表达式只进行了一次回溯。
(2).懒惰
源字符串:"Regex"
正则表达式:".*?"
看一下非贪婪模式的匹配过程。首先由第一个“"”取得控制权,匹配位置0位的“"”,匹配成功,控制权交给“.*?”。“.*?”取得控制权后,由于“*?”是忽略优先量词,在可匹配可不匹配的情况下,优先尝试不匹配,由于“*”等价于“{0,}”,所以在忽略优先的情况下,可以不匹配任何内容。从位置1处尝试忽略匹配,也就是不匹配任何内容,将控制权交给正则表达式最后的“””。
“"”取得控制权后,从位置1处尝试匹配,由“"”匹配位置1处的“R”,匹配失败,向前查找可供回溯的状态,控制权交给“.*?”,由“.*?”吃进一个字符,匹配位置1处的“R”,再把控制权交给正则表达式最后的“"”。
“"”取得控制权后,从位置2处尝试匹配,由“"”匹配位置1处的“e”,匹配失败,向前查找可供回溯的状态,重复以上过程,直到由“.*?”匹配到“x”为止,再把控制权交给正则表达式最后的“"”。
“"”取得控制权后,从位置6处尝试匹配,由“"”匹配字符串最后的“"”,匹配成功。
此时整个正则表达式匹配成功,其中“.*?”匹配的内容为“Regex”,匹配过程中进行了五次回溯。