首页 > 代码库 > 正则表达式基础知识02
正则表达式基础知识02
回溯引用:前后一致匹配
回溯引用(backreference)在文本匹配和文本替换操作里非常有用。
例子1:匹配HTML中任意一级的标题栏中的内容例如:<h1>nihao</h1>
模式1:<[hH][1-6]>.*?</[hH][1-6]> 【注意这里使用懒惰型的*】
但是这里模式不是正确的:例如:<H2>abcd</H3> 显示不是正确的
模式2:<[hH]([1-6])>.*?</[hH]\1> 正确
回溯引用匹配:模式的后半部分引用在前半部分中定义的子表达式【允许正则表达式模式引用前面的匹配结果。】
Note:回溯引用只能用来引用模式里的子表达式。
例子:找出某一段文本中所有连续重复出现的单词,在搜索某个单词第二次出现时这个单词必须是已知的。
[ ]+(\w+)[ ]+\1 匹配同一个单词连续出现两次
\1表示模式里的第一个子表达式,\2表示第二个子表达式
回溯引用在替换操作中的应用
替换要用到两个模式:搜索模式、替换模式
例子:
? 将所有HTML中的电子邮件替换成链接
要使用回溯引用:(\w+[\w\.]*@[\w\.]+\.[\w]+)
<a href=”mailto:$1”>$1</a> 【在JavaScript中使用\代$】
? 将用户信息数据库里的电话由313-555-1234改为(313)555-1234
搜索模式:(\d{3})(-)(\d{3})(-)(\d{4})
替换模式:($1)$3-($5)
大小写转换
元字符 | 说明 |
\E | 结束\L或\U转换 |
\l | 把下一个字符转化为小写 |
\L | 把\L到\E之间的字符转换为小写 |
\u | 把下一个字符转化为大写 |
\U | 把\U到\E之间的字符转化为大写 |
例子:
? 将<H1-6></H1-6>之间的字母转换为大写
搜索模式:(<[hH]1>)(.*?)(</[hH]1>)
替换模式:$1\U$2\E$3
前后查找(lookaround)
有时候要用正则表达式标记要匹配的文本的位置,因此要使用前后查找(对某一位的前后内容进行查找)
例子:把一个web页面的页面标题提取出来。HTML的标题是在<title></title>之前而这个标题又必须嵌套在<head></head>中
模式1:<[tT][iI][tT][lL][eE]>.*</[tT][iI][tT][lL][eE]>
要求:只需要标题内容,不符合
方案1:使用只表达式分为三部分,提取要的部分
方案1缺点:明知不是真正需要的东西还要检索,检索出来毫无意义(相当于先检索出来,在手动的删除)
真正的模式:它包含的匹配本身并不返回,而是用于确定正确的匹配位置,它并不是匹配结果的一部分—前后查找。
Note:前后查找中的前、后指模式与被查找的文本的相对位置而言,左为前。
向前查找
向前查找指定了一个必须匹配但不在结果中返回的模式。向前查找实际上是一个 子表达式,查找出现在匹配文本之前的字符(当不消费它)。向前查找时一个以?=开头的子表达式,需要匹配的文本在=后面。
向前查找(向后查找)匹配本身是又返回结果的,只是这个结果的字节长度永远为0而已。
例子
? 原始文本是URL地址,要提取其中的协议名部分
http://www.fota.com
https://mail.forta.com
ftp://ftp.forta.com
搜索模式1:.+(?=:)
说明1:被匹配的:并没有出现在最终的匹配结果中,即不消费它。
搜索模式2:.+(:)
说明2:匹配了:并且消费了:
向后查找
向后查找的操作符是?<=,使用时必须要在一个只表达式里,而且后面要跟着要匹配的文本。
Note:向前查找的长度是可变的,它可以包含.、+子类的元字符。而向后查找模式只能是固定长度。
例子
? 在一份产品目录中,只需要把其价格列出来即可。
格式:
ABC01: $23.45
HGG42: $5.31
XTC99: $899.0
Total items found: 3
模式1:\$[0-9.]+ 但是不想让$出现在结果中
后向模式:(?<=\$)[0-9-.]+
前向查找和后向查找结合
使用两者结合的方法来解决本章开始提出的问题:提取web网页中的标题名。
模式:(?<=\<[tT][iI][tT][lL][eE]>).*(?=</[tT][iI][tT][lL][eE]>)
对前后查找取非
上面的查找方式又称为正向前查找,正向后查找,这里的正是寻找匹配的事实。
负前后查找包括负向前查找、负向后查找。
负向前查找:将向前查找不与给定模式相匹配的文本;
负向后查找:将向后查找不与给定模式相匹配的为文本;
操作符 | 说明 |
(?=) | 正向前查找 |
(?!) | 负向前查找 |
(?<=) | 正向后查找 |
(?<!) | 负向后查找 |
例子:
例一:
文本:
I paid $30for 100 apples, 50 oranges, and 60 pears. I savd $5 on this order.
正则表达式:
(?<=\$)\d+
分析:
匹配了$30、$5但是不消费$,因此只是得到了30、5
正则表达式:
\b(?<!\$)\d+\b
分析:
负向后查找,结果中只包含那些不以$开头的数值,上述使用了\b规定了单词的边界,是因为若不使用\b,那么$30中的30也满足’(?<!\$)\d+’这个模式
嵌入条件
引入:
(123)456-7890和123-456-7890都是北美可接受的电话号码,而1234567890、(123)-456-7890和(123-456-7890)的格式不对,若现在要编写一个正则表达式只匹配可接受的格式,不匹配其他格式。
解决方案:
\(?\d{3}\)?-?\d{3}-\d{4}
正则表达式里面的条件
正则表达式中的条件使用?来定义,?(匹配前一个字符或表达式)、?=个?<=匹配前面或后面的文本。嵌入条件不外乎以下两种情况:1. 根据回溯引用进行条件处理;2. 根据前后查找进行条件处理。
1 回溯引用条件
回溯引用条件只在一个前面的子表达式搜索成功的情况下才允许使用一个表达式。
语法1:?(backreference)true-regex)
?表明是一个条件;
backreference:是一个回溯引用;
true-regex:一个只在backreference存在时才被执行的子表达式;
例子
? 需要把<IMG>标签全部找出来,若<IMG>是一个链接(<a></a>)的话需要把整个链接标签匹配出来。
数据格式:
<IMG src=http://www.mamicode.com/”imamges/pacer.gif”>
<A href=http://www.mamicode.com/”/search”>
搜索模式:
(<[Aa]\s+[^>]+>\s*)?<[iI][mM][gG]\s+[^>]+>(?(1)\s*</Aa>)
说明:
(<[Aa]\s+[^>]+>\s*)
用于匹配<A>或<a>因为后面有一个?表示该子表达式可有可无;
<[iI][mM][gG]\s+[^>]+>
匹配<IMG>以及其属性
(?(1)\s*</Aa>)
是一个回溯引用条件?(1) 表示若第一个回溯引用存在,则使用\s*</[Aa]>继续进行匹配。
语法2:?(backreference)true-regex|false-regex)
false-regex:z只有在backreference不存在时才被执行
例子:对于前面电话号码问题的解决方案,这里使用回溯引用的解法是
搜索模式:(\()?\d{3}(?(1)\)|-)\d{3}-\d{4}
2.前后查找条件
前后查找条件只在一个向前查找后向后查找取得成功的情况下才允许一个表达式被引用。只需要将回溯引用(括号里的回溯引用编号)替换为一个完整的前后查找表达式就行了。
例子:如何匹配美国的邮政编码,有两种格式:12345-ZIP格式,12345-6789—ZIP+4格式,只有ZIP+4才允许分隔
解决方案1:
搜索模式:\d{5}(.\d{4})? 【这个对33333.则能够匹配】
如何找到一个能够不匹配那些格式不正确的ZIP编码
解决方案2:
搜索模式:\d{5}(?(?=-)-\d{4})
正则表达式基础知识02