正则表达式实质就是一串用来匹配相关文本的表达式
正则表达式的四种功能
为什么使用正则表达式?我们知道,在程序处理中,经常涉及文本处理,在这样一个恶劣的生存领域,除了正则表达式和更高级的parser技术外,可以说别无利器。有了正则表达式,就意味着你有了四大基本功能:
1. 检验相关文本段是否存在
2.从资源中 提取相关文本段
3.从资源中 分割相关文本段
4. 替换资源中的相关文本段
可以看出,功能2和功能3是有点重复的,事实上,这几个功能都重复。。因为正则表达式核心功能就是" 文本匹配",对于文本的其他操作都可以基于匹配实现。要掌握这把利器,需要循序渐进地练习,但更多情况下,吓吓坏人,懂得"挥两下"就好了,
快速建立学习的框架
正则表达式处理的文本是由一个个字符构成的,最基本的操作当然也是针对单个字符的,这是框架的第一条主线。对多个字符同时进行操作,涉及到分组的概念,这是框架的第二条主线。
第一条主线:
元字符与普通字符 --> 字符组 --> 排除型字符组 --> 量词 --> 贪婪与懒惰
第二条主线:
分组 --> 多选结构 --> 引用分组 --> 命名分组
小分支:
锚点
以上是我归纳的有关正则表达式的学习路线,属于一次性可接纳吸收的知识,若只是需要“挥两下”正则表达式,这就足够了。接下来开始正文!
正则表达式是由元字符和普通字符构成的。元字符用来实现一些特殊的功能,普通字符则用来匹配文本字符。关于正则表达式有什么元字符,你可以在 《正则表达式元字符及说明》找到答案,这里就不再啰嗦了。
如果你想匹配某个字符,就在正则表达式中敲上那个字符,但如果你想匹配的字符,恰好是个元字符,那就需要转义。
转义只有一种方法,外加一种特殊情况(可以忽略)。这种方法就是使用转义符"\",将元字符转成普通字符。这里列举了几种常见情况。
元字符相关的文本 | 转义方法 |
---|---|
- | \- |
* | \* |
+ | \+ |
? | \? |
*? | \*\? |
+? | \+\? |
{n} | \{n} |
{m,n} | \{m,n} |
{m,} | \{m,} |
{,n} | \{,n} |
. | \. |
[mn] | \[mn] |
1.2字符组
字符组名字虽然带有“组”字,但实质还是单个字符。它的表达方式为[],中间放东西,比如[0123456789]只匹配一个数字,代表0至9这十个数字都可以被匹配,也可以写出[783461250],还可以用范围表示法表示,如[0-9]。此外字母也可以,如[a-z],因为其本质都是ASCII码。若还想简化,可以使用字符组简记法\d替代[0-9],各简记法如下表所示:
字符组简记法 | 等价记法 |
\d | [0-9] |
\w | [0-9a-zA-Z] |
\s | [ \t\r\n\v\f] |
\D | 除\d之外的所有字符 |
\W | 除\w之外的所有字符 |
\S | 除\s之外的所有字符 |
因而由上表可以得出另外一个结论,<<[\s\S]>>可以匹配任意一个字符,同理<<[\w\W]>>和<<[\d\D]>>也是
这里还有一点需要注意,<<.>>点号其实不能匹配任意字符,因为\n换行符是个例外,真正能匹配任意字符的,只有以上说的这种形式
1.3排除型字符组
关于排除型字符组,你只需要知道三个点:1.排除型字符组是字符组的一种,用来排除一个不想匹配的字符。
2.写法为[^reg],reg是你不想匹配的字符。
3.[^reg]是必须匹配一个字符的,只是不匹配你排除的字符而已。
1.4量词:
若想匹配多个相同的字符,如555555,当然可以继续用555555这个正则表达式来匹配,但更简单地是使用量词,如:5{6}可以替代555555。量词可以认为只有两种,一种是{}这样的,如下表所示:
量词 | 说明 |
{n} | 之前的元素必须出现n次 |
{n,m} | 之前的元素最少出现n次, 最多出现m次 |
{m,} | 之前的元素最少出现m次 出现次数无上限 |
{0,n} | 之前的元素可以不出现 但最多出现n次 |
另外一种叫量词简记法,如下表所示:
量词简记法 | {m,n}等价形式 | 说明 |
* | {0,} | 可能出现,也可能不出现,出现次数无上限 |
+ | {1,} | 至少出现1次,出现次数没有上限 |
? | {0,1} | 至多出现1次,也可能不出现 |
1.5贪婪及懒惰:
正则表达式一般是贪婪的,什么意思?贪婪指的是,它会尽可能使匹配的量词最大化,但也可以让它变得懒惰,即只要匹配到符合要求的了,就停止匹配,如:
贪婪:<<[/s/S]*ivan>> 去匹配字符串“My name is ivan, not that ivan”,它会匹配整个字符串"My name is ivan, not that ivan"
懒惰:<<[/s/S]*?ivan>> 去匹配字符串“My name is ivan, not that ivan”,则匹配"My name is ivan"
懒惰模式与贪婪模式的写法如下:
贪婪 | 懒惰 |
* | *? |
+ | +? |
? | ?? |
{m,n} | {m,n}? |
{m,} | {m,}? |
{,n} | {,n}? |
------------------------------------------------------------------------------------累死我了,下面的星期天旅游回来再写------------------------------------------------------------------
2.1分组:
刚才讨论的都是针对单个字符的操作,若想扩展到多个字符的情况,那就需要用到分组的功能。分组很简单就是用()将想要一起操作的多个字符括起来。若想对分组作量词操作,可以在分组后面紧跟量词,如(ab2){3},可以匹配ab2ab2ab2。当然除了量词操作外,还有几种针对分组的功能,常用的有:多选结构,引用分组,命名分组。
表示方法就是(|),括号内|左右可分别填入字符,如(reg1|reg2)。多选结构其实就是或的意思。需要注意的是,若文本里,reg1和reg2都能匹配,正则表达式会按照顺序从左到右匹配,因而这里将匹配到reg1,而不是reg2。如在文章里,用多选结构(河南|河南省)匹配相应的文本,则匹配出来的都将是“河南”,包括原本文章中“河南省”中的“河南”。
正则表达式中一般会有多个分组,每个分组匹配完成后,正则表达式都会记录下这个分组匹配到的文本,这意味着,可以调用各个分组匹配到的文本。
引用分组的表达方法
表达形式就是\接数字,比如\3,即表示第3个文本匹配到的文本。一个正则表达式一般会有多个分组,有可能是嵌套分组,分组的编号,按照左括号,从左到右依次增加,如:
(((\d{3})-(\d{2}))-(\d{2}))
0 | | | | | | | | |
1 | | | | | | | | |
2 | | | | | | |
3 | | | | |
4 | | |
5 |
2.4命名分组:
除了按照编号引用分组外,你还可以命名分组,其结构如下图所述:
字符串: 2013 - 05 - 27
表达式:(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})
分组名: year month day
命名分组的表达式有很多,上面是Python的记法,用(?P<name>...)来分组。
根据编号或命名引用分组有什么作用呢?这里分别以匹配,替换及提取为例,说明如下:
操作 | 匹配字符串 | 正则表达式 | 结果 | 说明 |
匹配 | shoot | ([a-z])\1 | oo | 用于查找连续重叠字母。括号内[a-z]匹配第一个字母, \1用于反向引用,实现查找连续字母的功能 |
替换 | 2013-05-27 | re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\2/\3/\1", "2013-05-27") | 05/27/2013 | re.sub()是Python与正则表达式相关的函数, 它的第一个参数使用正则表达式匹配字符串, 第二个参数使用引用分组进行替换操作, 第三个参数是源字符串 |
提取 | 2012-03-14 | re.search(r"(\d{4})-(\d{2})-(\d{2})", "2012-03-14").group(3) | 14 | re.search()同样是Python与正则表达式相关的函数, 它的第一个参数使用正则表达式匹配字符串, 第二个参数是源字符串,group(3),代表提取的编码 为3的分组,即/3 |
针对引用分组,需要特殊说明的是,当分组匹配成功后,引用分组也被固化为匹配到的文本了。
3.1锚点:
锚点和一般的正则表达式符号不同,它不匹配任何字符。相反,他们匹配的是字符之前或之后的位置。
“^”匹配一行字符串第一个字符前的位置。<<^a>>将会匹配字符串“abc”中的a。<<^b>>将不会匹配“abc”中的任何字符。
类似的,$匹配字符串中最后一个字符的后面的位置。所以<<c$>>匹配“abc”中的c。
这里介绍三个常用的锚点:
锚点 | 说明 |
^ | 行首 |
$ | 行尾 |
\b | 单词的开始或结束 (单词边界) |
--------------------------------------------------------------正文部分至此结束---------------------------------------------------------------------
以上部分属于我一次性能记下的有关正则表达式的基础内容。学的时间很短,但是写这文章花费的时间却很长,主要难点在于整理出一个知识的框架,这样即便过了很久,也不会忘记相关的内容。实质上有关正则表达式的基础内容还有几方面没有涵盖到:1.分组的非捕获分组
2.分组的断言,环视
3.匹配模式
这三部分内容其实也比较简单,可以参考相关的博文,过一遍基本就会用了。
最后附上本文的参考资料:
1.《正则指引》
2.http://dragon.cnblogs.com/archive/2006/05/08/394078.html
3.http://www.cnblogs.com/deerchao/archive/2006/08/24/zhengzhe30fengzhongjiaocheng.html
都是中文的,推荐大家看看,另外还有一个专门介绍正则表达式的博客