多字符匹配的一般形式
为什么需要量词?因为使用量词可以方便的匹配多个字符。以匹配邮政编码为例,其是由6位数字构成的字符串,比如201203。根据之前学习的知识,匹配这样的字符串需要使用正则表达式\d\d\d\d\d\d。而使用量词进行匹配则只需要写成\d{6}。
量词可以表达不确定的长度,其通用形式是{m,n},其中m和n是两个数字,m是下限,n是上限(均是闭区间),m和n共同限定了之前的元素能够出现的次数。
\d{m,n}表示所匹配的数字字符串长度,最短是m个字符,最长是n个字符。
如果不确定长度的上限,可以省略n值,只给出m值,例如\d{m,},表示数字字符串的长度必须在m个字符之上。
量词限定的出现次数一般都有明确的下限,如果没有,则默认为0。
注:量词中的逗号之后绝不能有空格。
| 量词 | 说明 |
| {n} | 之前的元素必须出现n次 |
| {m,n} | 之前的元素最少出现m次,最多出现n次 |
| {m,} | 之前的元素最少出现m次,出现次数无上限 |
| {0,n} | 之前的元素可以不出现,也可以出现,最多出现n次(在某些语言中可以写为{,n}) |
常用量词
{m,n}是量词表达的通用形式,在正则表达式中还存在三个作为“量词简记法”的常用量词,如下表:| 常用量词 | {m,n}等价形式 | 说明 |
| * | {0,} | 可能出现,也可能不出现,出现次数没有上限 |
| + | {1,} | 至少出现1次,出现次数没有上限 |
| ? | {0,1} | 至多出现1次,也可能不出现 |
一些使用常用量词的例子:
- 针对美式英语和英式英语单词拼写的使用,如travell?er。
- 针对http和https两种协议的匹配,如https?。
- 匹配HTML中的所有tag,如<[^>]+>(该正则表达有一点缺陷,以前一篇文章和本文中的知识无法解决)。
| 匹配所有tag的表达式 | tag分类 | 匹配分类tag的表达式 |
| <[^>]+> | Open tag | <[^/>][^>]*> |
| | Close tag | </[^>]+> |
| | Self-closing tag | <[^>/]+/> |
- 匹配双引号字符串,如”[^”]*”。
上面给出用于匹配open tag的正则表达式,也能够匹配self-closing tag。以目前已学知识无法解决。
特殊元字符:点号
一般文档都说,点号可以匹配“任意字符”,但事实是,点号可以匹配除换行符\n之外的任意字符。如果非要匹配“任意字符”,有两种办法:在正则匹配时指定使用单行模式(目前不解释细节),在这种模式下,点号可以匹配换行符;或者使用之前说过的通配字符组[\s\S](也可以是[\d\D]或[\w\W])。点号的使用容易出现滥用,比如随意使用.*或.+。
例如,之前我们使用”[^”]*”匹配双引号字符串,而“图省事”的做法是”.*”。这种用法会出现意外,因为用”.*”匹配双引号字符串,不但可以匹配正常的双引号字符串”quoted string”,还可以匹配格式错误的字符串”quoted string” and another”。另外”.*”无法匹配有换行符的情况。
这个问题简答的讲,是因为所使用量词的类型导致。之前介绍过的量词都属于匹配优先量词(greedy quantifier,也称作贪婪量词)。这类量词的特点是,在拿不准是否要匹配的时候,优先尝试匹配,并记下这个状态,以备将来进行回溯(backtracking)。例如下图所示过程
匹配优先量词使用的常见场景:
- 文件名解析(例如使用^.*/对/usr/local/bin/python进行路径匹配;用[^/]*$对文件名匹配)
忽略优先量词使用的常见场景:
- 匹配多段javascript代码(<script type=”text/javasript”>...</script>);
- 匹配类似C语言那样的多行注释(行尾注释//...,和多行注释/*...*/);
- 提取HTML代码中的超链接(<a href=”http://somehost/somepath”>text</a>);
目前已知的匹配优先量词和其对应的忽略优先量词如下表所示
| 匹配优先量词 | 忽略优先量词 | 限定次数 |
| * | *? | 可能不出现,也可能出现,出现次数没有上限 |
| + | +? | 至少出现1次,出现次数没有上限 |
| ? | ?? | 至多出现1次,也可能不出现 |
| {m,n} | {m,n}? | 出现次数最少为m次,最多为n次 |
| {m,} | {m,}? | 出现次数最少为m次,没有上限 |
| {,n} | {,n}? | 可能不出现,也可能出现,最多出现n次 |
匹配优先量词和忽略优先量词逐一对应,只是在对应的匹配优先量词之后添加?,两者限定的元素能出现的次数也一样,遇到不能匹配的情况同样需要回溯;唯一的区别在于,忽略优先量词会优先选择“忽略”,而匹配优先量词会优先选择“匹配”。另外,匹配优先量词只需要考虑自己限定的元素能够匹配即可,而忽略优先量词必须兼顾它所限定的元素和之后的元素,效率自然大大降低,当处理字符串很长时,尤为明显。
问题:C语言的两种注释方式,一种是在行末,以//开头;另一种可以跨多行,以/*开头,以*/结束。要匹配这两种注释,如何写正则表达式?
忽略优先量词在HTML页面解析中的应用:
| 类型 | 正则表达式 |
| 匹配table | <table[\s>][\s\S]+?</table> |
| 匹配tr | <tr[\s>][\s\S]+?</tr> |
| 匹配td | <td[\s>][\s\S]+?</td> |
注:因为tag是不区分大小写的,所以如果还希望匹配大小写的情况,则必须使用字符组,table写成[tT][aA][bB][lL][eE]。
在实际的HTML代码中,table、tr、td这三个元素经常是嵌套的,它们之间存在着包含关系。但是仅仅使用正则表达式匹配,并不能得到这种包含关系信息。换句话说,正则表达式只能进行纯粹的文本处理,单纯依靠它不能整理出层次结构;如果希望解析文本的同时构建层次结构信息,则必须将正则表达式配合程序代码一起使用。
转义
之前介绍过元字符的转义,这里要介绍的是量词的转义。对于常用量词所使用的字符+、*、?来说,如果希望表示这三个字符本身,直接添加反斜线,变为\+、\*、\?即可。但是在一般形式的量词{m,n}中,虽然具有特殊含义的字符不止一个,转义时却只需要给第一个{添加反斜线即可,也就是说,如果希望匹配字符串{m,n},则正则表达式必须写成\{m,n}。
需要注意的是针对忽略优先量词的转义,因为其需要对两个量词全部转义。例如,如果要匹配字符串*?,正则表达式必须写作\*\?,而不是\*?。
下表为各种量词的转义
| 量词 | 转义形式 |
| {n} | \{n} |
| {m,n} | \{m,n} |
| {m,} | \{m,} |
| {,n} | \{,n} |
| * | \* |
| + | \+ |
| ? | \? |
| *? | \*\? |
| +? | \+\? |
| ?? | \?\? |
本文详细介绍了正则表达式的使用原则、量词、特殊元字符点号、匹配优先量词与忽略优先量词的概念及其应用案例。通过具体实例展示了如何使用正则表达式进行文本匹配与解析。


被折叠的 条评论
为什么被折叠?



