正则表达式语法简单写法
2017-01-04 14:06
405 查看
转:http://www.cnblogs.com/cdinc/p/5793142.html
一 元字符
正则表达式中的特殊字符被称作元字符,常用的元字符如下:. 点,匹配除换行符以外的任意字符
\w 匹配数字、字母和下划线(可以匹配汉字)
\s 匹配空白字符,如空格、换行符、制表符等
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结尾
\(特殊) 转义字符。如果需要匹配的内容含有元字符本身的,需要使用转义字符进行转义
“.”的用法(使用python3.x进行举例,具体的python3.x的正则表达式的用法请参考http://www.cnblogs.com/cdinc/p/5789429.html):
string='qq14717287xx@qq.com&10010/10086' pattern=r'.com.' item=re.search(pattern,string) print(item.group())
运行结果是:
.com&
可以看到匹配的结果是com和前一个字符和后一个字符,这个就是这个“.”的作用。
“\w”的用法:
string='qq14717287xx@qq.com&10010/10086' pattern=r'7287\w' item=re.search(pattern,string) print(item.group())
运行结果是:
7287x
可以看到匹配的结果是“7287”后面再多加一个字母,这就是“\w”的用法。
“\s”的用法:
string='qq14717287xx@qq. com&10010/10086' pattern=r'\scom' item=re.search(pattern,string) print(item.group())
运行结果是:
com
在com前面又匹配到了一个空格
“\d”的用法:
string='qq14717287xx@qq. com&10010/10086'
pattern=r'qq\d'
item=re.search(pattern,string)
print(item.group())
运行结果是:
qq1
“\b”的用法:
string='qq14717287xx@qq. com&10010/10086'
pattern=r'\bcom\b'
item=re.search(pattern,string)
print(item.group())
运行结果是:
com
将“com”作为一个单词进行匹配。因为匹配的是单词的开头或者结尾,所以如果匹配的是“om\b”也可以匹配上,是com单词的结尾,但是“\bom”则无法匹配,因为om前面有c,认为com是一个单词,“om”并不是单词的开始位置,所以无法匹配。
“^”的用法:
string='qq14717287xx@qq. com&10010/10086'
pattern=r'^qq'
item=re.search(pattern,string)
print(item.group())
运行结果是:
匹配以“qq”开头,所以能够匹配上,如果是“^com”,则无法匹配上。
“$”的用法:
string='qq14717287xx@qq. com&10010/10086'
pattern=r'0086$'
item=re.search(pattern,string)
print(item.group())
运行结果是:
0086
匹配以0086结尾,能够匹配上。填写正则表达式的时候,$符号要放在匹配字符串或者公式的后面。
“\”(转移字符)的用法:
string='qq14717287xx@qq.com$10010/10086' pattern=r'com\$' item=re.search(pattern,string) print(item.group())
运行结果是:
com$
可见本次就是纯粹的查找的“com$”,而没有将$作为元字符处理。
二 重复
正则表达式中提供了几种重复的方式,毕竟如果匹配三个字母使用“\w\w\w”的方式太不方便了,如果是三个还好,如果是十个、二十个呢。* 重复零次或者多次
+ 重复一次或者多次
? 重复零次或者一次
{n} 重复n次
{n,} 重复n次或者更多次
{n,m} 重复n次到m次
“*”的用法:
string='qq14717287xx@qq.com$10010/10086' pattern=r'\w*' item=re.search(pattern,string) print(item.group())
运行结果是:
qq14717287xx
可以看到匹配到了多次字母和数字。
“+”的用法:
string='qq14717287xx@qq.com$10010/10086' pattern=r'\w+!*' item=re.search(pattern,string) print(item.group())
运行结果是:
qq14717287xx
结果是匹配到了多个字母、数字,因为匹配字符串中没有“!”。如果匹配的是“\w+!+”,则无法匹配。这从另一个方面说明了“*”和“+”的区别。
“?”的用法:
string='qq14717287xx@qq.com$10010/10086' pattern=r'\w+@?' item=re.findall(pattern,string) print(item)
运行结果是:
['qq14717287xx@', 'qq', 'com', '10010', '10086']
可以看到,使用匹配的字符后面含有1个或没有“@”符号
“{n}”的用法:
string='qq14717287xx@qq.com$10010/10086' pattern=r'\w{5}' item=re.findall(pattern,string) print(item)
运行结果是:
['qq147', '17287', '10010', '10086']
对于数字、字母重复了五次的地方进行了匹配。
“{n,}”的用法:
string='qq14717287xx@qq.com$10010/10086' pattern=r'\w{5,}' item=re.findall(pattern,string) print(item)
运行结果是:
['qq14717287xx', '10010', '10086']
匹配了数字、字母重复5次及以上的地方。
“{n,m}”的用法:
string='qq14717287xx@qq.com$10010/10086' pattern=r'\w{5,8}' item=re.findall(pattern,string) print(item)
运行结果是:
['qq147172', '10010', '10086']
可以看到,因为限定了重复次数(5-8次),所以第一个组合(qq14717287xx)被分开进行匹配。
三 特定字符查找
1、单字查找查找字母、数字我们已经知道了,但是如果我们只是想查找特定字符怎么办?比如我只想找到有没有aeiou这几个字母怎么办?没关系,那就把他们都列出来就好了,写作[aeiou]
string='qq14717287xx@qq.com$10010/a10086' pattern=r'.{4}[aeiou].{2}' item=re.findall(pattern,string) print(item)
运行结果是:
['qq.com$', '010/a10']
可以看到,匹配了“o”和“a”前面的四个字符和后面的两个字符。
列在[]中的字符只匹配是否含有其中的字符,而[]中的写法也有很大的自由度。
比如想匹配数字,可以不用写为[0123456789],而是写为[0-9],这两个的含义是相同的。
同理,小写字母可以写为[a-z],大写字母可以写为[A-Z],匹配英文可以写为[a-zA-Z]
string='qq14717287XX@qq.com$10010/a10086' pattern=r'[0-9]{5}' item=re.findall(pattern,string) print('匹配数字:',item) pattern=r'[a-zA-Z]{2}' item=re.findall(pattern,string) print('匹配字母:',item) pattern=r'[a-zA-Z0-9]{4}' item=re.findall(pattern,string) print('匹配数字和字母:',item)
运行结果是:
匹配数字: ['14717', '10010', '10086'] 匹配字母: ['qq', 'XX', 'qq', 'co'] 匹配数字和字母: ['qq14', '7172', '87XX', '1001', 'a100']
2、分组查找
如果我们想重复多个字符应该怎么办呢?我们可以使用小括号来指定子表达式(也叫做分组),我们也可以指定分组重复的次数。比如我想匹配一个IP地址,我们可以这样写:
string="Thiscomputer's IP is 192.168.0.1"
pattern=r'(\d{1,3}\.){3}\d{1,3}'
item=re.search(pattern,string)
print(item.group())
运行结果是:
192.168.0.1
于是我们就得到了一个IP地址(有效性不进行验证,验证方法比较复杂,但是网上也有,可以百度之)。
3、反义查找
我们已经知道几种查找的元字符了,但是如果我们就是不想要查找那几种字符怎么办呢。没关系,正则表达式还提供反义查找方式。
\W 匹配任意非\w的字符
\S 匹配任意非\s的字符
\D 匹配任意非\d的字符
\B 匹配非单词开头或结尾的部分
[^q] 匹配非q字符的部分
[^aeiou] 匹配非aeiou的部分
“\W”的用法:
string='qq14717287xx@qq.com&10010/10086' pattern=r'\W+.{0,3}' item=re.findall(pattern,string) print(item)
运行结果是:
['@qq.', '&100', '/100']
“\S”的用法:
string='qq14717287 xx@qq. com&10010/10086'
pattern=r'\S+'
item=re.findall(pattern,string)
print(item)
运行结果是:
['qq14717287', 'xx@qq.', 'com&10010/10086']
“\D”的用法:
string='qq14717287xx@qq.com&10010/10086' pattern=r'\D+' item=re.findall(pattern,string) print(item)
运行结果是:
['qq', 'xx@qq.com&', '/']
“\B”的用法:
string='qq14717287xx@qq.com&10010/10086' pattern=r'.{2}\B00\B.{2}' item=re.findall(pattern,string) print(item)
运行结果是:
['&10010', '/10086']
“^”的用法:
string='qq14717287xx@qq.com&10010/10086' pattern=r'[^7]+' item=re.findall(pattern,string) print(item)
运行结果是:
['qq14', '1', '28', 'xx@qq.com&10010/10086']
匹配非7的部分。
四 分支条件
正则表达式也支持类似于OR的方式,使用“|”符号连接几个表达式,只要其中一个表达式匹配上就算匹配。比如我们有几个电话,既有010-12345678的固定电话方式,又有15812345678的手机方式,我们应该怎么匹配呢?
string1='010-12345678' string2='15812345678' pattern=r'\d{3}-\d{8}|\d{11}' item=re.findall(pattern,string1) print(item) item=re.findall(pattern,string2) print(item)
运行结果:
['010-12345678'] ['15812345678']
可以看到,我们使用相同匹配表达式都能够匹配到需要的内容。
但是,需要注意的是,这种方式的匹配是有顺序的。比如美国的邮政编码是一个5位数字或者是一个用连字符连起来的9位数字,那么它的匹配表达式的写法是:\d{5}-\d{4}|\d{5},如果顺序颠倒,那么就只会匹配5个数字而不会再匹配用连字符连起来的9位数字了,因为只要能够匹配上就不会再考虑后面的表达式了。所以使用分枝条件的时候需要注意条件的顺序。
五 注释
在正则表达式中,我们可以使用(?#content)来使用注释。string='qq14717287xx@qq.com&10010/10086'
pattern=r'\D+(?#This is acomment)'
item=re.findall(pattern,string)
print(item)
运行结果是:
['qq', 'xx@qq.com&', '/']
可以看到,注释内容并没有影响匹配结果。
我们还可以将正则表达式写为多行,通过设置忽略多余的空白字符选项,可以将注释写为只是#开头,这种方式下,#的后面至行末都被判断为注释。
string='qq14717287xx@qq.com&10010/10086'
pattern=r'''\D+ #This is acomment
.{2} #This is acomment too
\d+ #This is also acomment'''
item=re.findall(pattern,string,re.X)
print(item)
运行结果是:
['qq14717287', 'xx@qq.com&10010', '/10086']
六 贪婪匹配与懒惰匹配
正则表达式默认匹配尽可能多的字符。string='this is a demo text!' pattern=r't.*t' item=re.findall(pattern,string) print(item)
运行结果是:
['this is a demo text']
这个表达式匹配了最长的以t开始中间没有或多个字符再以t结尾的一个字段。这种匹配模式就被称为贪婪模式。
但是有时候我们的需求是需要匹配尽可能少的字符,这种方式在正则表达式中被成为懒惰模式。需要匹配懒惰模式,只需要在限定符后面加入一个?就可以了。
懒惰模式有以下几种形式:
*? 重复任意次,但是匹配尽可能少的字符。
+? 重复1次或者多次,但是匹配尽可能少的字符。
?? 重复0次或者1次,但是匹配尽可能少的字符。
{n,m}? 重复n次到m次,但是匹配尽可能少的字符。
{n,}? 重复n次以上,但是匹配尽可能少的字符。
以下看一下它们的用法及匹配结果:
“*?”:重复任意次,但是匹配尽可能少的字符。
string='this is a demo text!' pattern=r't.*?t' item=re.findall(pattern,string) print(item)
运行结果是:
['this is a demo t']
这样就就匹配了t和t之间最少的字符。but,为什么匹配结果不是“text”呢?因为正则表达式有一个优先级更高的规则,最先开始的匹配拥有最高优先权。
“+?”:重复1次或者多次,但是匹配尽可能少的字符。
string='this is a demo text,too!' pattern=r'd.+o' item=re.findall(pattern,string) print('普通(贪婪)匹配结果:',item) pattern=r'd.+?o' item=re.findall(pattern,string) print('懒惰匹配结果:',item)
运行结果是:
普通(贪婪)匹配结果: ['demo text,too'] 懒惰匹配结果: ['demo']
“??”:重复0次或者1次,但是匹配尽可能少的字符。
string='this isi a demo text,too!' pattern=r't.?o' item=re.findall(pattern,string) print('普通(贪婪)匹配结果:',item) pattern=r't.??o' item=re.findall(pattern,string) print('懒惰匹配结果:',item)
运行结果是:
普通(贪婪)匹配结果: ['too'] 懒惰匹配结果: ['to']
“{n,m}?”:重复n次到m次,但是匹配尽可能少的字符。
string='this isi a demo text,too!' pattern=r't.{2,5}t' item=re.findall(pattern,string) print('普通(贪婪)匹配结果:',item) pattern=r't.{2,5}?t' item=re.findall(pattern,string) print('懒惰匹配结果:',item)
运行结果是:
普通(贪婪)匹配结果: ['text,t'] 懒惰匹配结果: ['text']
“{n,}?”重复n次以上,但是匹配尽可能少的字符。
string='this isi a demo text,too!' pattern=r't.{1,}i' item=re.findall(pattern,string) print('普通(贪婪)匹配结果:',item) pattern=r't.{1,}?i' item=re.findall(pattern,string) print('懒惰匹配结果:',item)
运行结果是:
普通(贪婪)匹配结果: ['this isi'] 懒惰匹配结果: ['thi']
七 分组
有时我们给定的匹配条件很多,但是需要的却不多。比如这个字符串“isi 1234 isi apple isi”,加入我们只想要“isi”中间的内容该怎么匹配呢?如果只用之前给的方法没有办法取出来,这就要说道分组了。分组就是将整个正则表达式分成不同的组,只获取不同组匹配的内容。
其中分组使用“()”来区分,括号内匹配的内容为一个组。
示例如下:
string='qq14717287xx@qq123456.com&10010/10086' pattern=r'(qq\d+).*?(qq\d+)' item=re.match(pattern,string) print('总共匹配到%s个数据。'%len(item.groups())) for i in range(len(item.groups())+1): print('第%d个数据是:%s'%(i,item.group(i)))
运行结果是:
总共匹配到2个数据。 第0个数据是:qq14717287xx@qq123456 第1个数据是:qq14717287 第2个数据是:qq123456
可以看到,默认分组都是按照号码自动分配。
但是明明匹配到了两个数据,为什么有三个显示呢?这是因为分组中,分组0表示全部正则表达式,所以第0个数据就是'qq\d+.*?qq\d+'的匹配结果。
有时候我们就是这么耿直,我们不想用你自动分配的号码,我想自己给匹配的字符串命名。这也能够实现,只要使用“(?P<name>pattern)”的方式就可以了。(以下为python3.x的实现方式,其他语言可能会有差别,但是原理相似)。
string='qq14717287xx@qq123456.com&10010/10086' pattern=r'(?P<aaa>qq\d+).*?(?P<bbb>qq\d+)' item=re.match(pattern,string) print(item.group("aaa")) print(item.group('bbb'))
运行结果是:
qq14717287 qq123456
但是有时我们又不想给某一个分组分配名字,连系统默认分配的号码都不想给他,也能够实现(至今没有发现这种方式存在的意义-_-|||)。
string='qq14717287xx@qq123456.com&10010/10086' pattern=r'(?P<aaa>qq\d+).*?(?:qq\d+)' item=re.match(pattern,string) print('总共匹配到%s个数据。'%len(item.groups())) for i in range(len(item.groups())+1): print('第%d个数据是:%s'%(i,item.group(i)))
运行结果是:
总共匹配到1个数据。 第0个数据是:qq14717287xx@qq123456 第1个数据是:qq14717287
可以看到,这次我们并没有匹配到第2个内容
所以,分组的情况分为以下几种:
(pattern) 匹配pattern,系统自动为组分配号码
(?P<name>pattern) 匹配pattern,并将组命名为name
(?:pattern) 匹配pattern,不捕获匹配的文本,也不分配号码
八 后向引用
后向引用可以用来匹配与某个分组相同的部分,提供查找重复字符组的方便的方法。我们可以通过示例来进行了解。
string='qq14717287xx@qq14723456.com&10010/10086' pattern=r'(qq\d+).*?(\1)' item=re.match(pattern,string) print('总共匹配到%s个数据。'%len(item.groups())) for i in range(len(item.groups())+1): print('第%d个数据是:%s'%(i,item.group(i)))
运行结果是:
总共匹配到2个数据。 第0个数据是:qq14717287xx@qq147 第1个数据是:qq147 第2个数据是:qq147
其中\1表示第一个分组的内容,两个分组相同并且符合匹配方式的部分的是"qq147",所以都匹配到了"qq147"。
如果我们将第二个字符串换为qq123456之后会发生什么呢?
string='qq14717287xx@qq123456.com&10010/10086' pattern=r'(qq\d+).*?(\1)' item=re.match(pattern,string) # item=re.findall(pattern,string) print('总共匹配到%s个数据。'%len(item.groups())) for i in range(len(item.groups())+1): print('第%d个数据是:%s'%(i,item.group(i)))
运行结果是:
总共匹配到2个数据。 第0个数据是:qq14717287xx@qq1 第1个数据是:qq1 第2个数据是:qq1
两个分组相同并且符合匹配方式的部分的只有"qq1",所以只匹配到了"qq1"。
如果已经给分组进行了命名呢?也没有问题,只需要将代表分组号码的"\1"换为分组名称"?P=aaa"即可。
string='qq14717287xx@qq14723456.com&10010/10086' pattern=r'(?P<aaa>qq\d+).*?(?P=aaa)' item=re.match(pattern,string) print('总共匹配到%s个数据。'%len(item.groups())) for i in range(len(item.groups())+1): print('第%d个数据是:%s'%(i,item.group(i)))
运行结果是:
总共匹配到1个数据。 第0个数据是:qq14717287xx@qq1 第1个数据是:qq1
可以看到和之前的匹配结果相同,但是第二个分组并没有进行捕获,真不知道是不是一个好消息。
九 零宽断言
我们想要使用一些匹配规则作为位置,只匹配前面或者后面的内容,那应该怎么实现呢?这就要说道断言了,断言指定了一个位置。我们还是通过例子来看吧。
(?=pattern)它断言自身出现的位置的前面能匹配需要匹配的内容
string='qq14717287xx@qq123456.com&10010/10086' pattern='\d+(?=\D+)' item=re.findall(pattern,string) print(item)
运行结果是:
['14717287', '123456', '10010']
可以看到,我们找到了不是数字的字符前面的数字。需要注意的是,断言本身并不是匹配结果。
(?<=pattern)它断言自身出现的位置的后面能匹配需要匹配的内容
string='qq14717287xx@qq123456.com&10010/10086' pattern='(?<=\d)\D+' item=re.findall(pattern,string) print(item)
运行结果是:
['xx@qq', '.com&', '/']
注意,这种方式下,\d后不能加*、+、?,因为这种方式不支持不定长度正则表达式(如果有错误,欢迎指正)。
(?=pattern)它断言需要匹配的内容后面不跟随pattern
string='qq14717287xx@qq123456.com&10010/10086' pattern='\d+(?!\D)' item=re.findall(pattern,string) print(item)
运行结果是:
['1471728', '12345', '1001', '10086']
(?<!pattern)它断言需要匹配的内容前面不跟随pattern,同样的,这种方式下,pattern后不能加*、+、?
string='qq14717287xx@qq123456.com&10010/10086' pattern='(?<!\D)\d+' item=re.findall(pattern,string) print(item)
运行结果是:
['4717287', '23456', '0010', '0086']
相关文章推荐
- msql 正则表达式
- 正则表达式
- JavaScript正则表达式详解
- Mootools 1.2教程 正则表达式
- 批处理FINDSTR正则表达式用法实例分析
- vbs正则表达式代码
- C#正则表达式Regex类的常用匹配
- C#中利用正则表达式将人民币金额转换为大写汉字
- C#使用正则表达式实现首字母转大写的方法
- 简述MySQL 正则表达式
- php中看实例学正则表达式
- PHP正则表达式之定界符和原子介绍
- PHP下常用正则表达式整理
- 批处理 正则表达式(findstr) 整理
- 详解C#正则表达式Regex常用匹配
- C#正则表达式的6个简单例子
- 正则表达式(语法篇推荐)
- JavaScript类型系统之正则表达式
- 详解JS正则replace的使用方法