正则表达式语法简单写法

转: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

  匹配以“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="This computer'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 a comment)'
item=re.findall(pattern,string)
print(item)

  运行结果是:

['qq', 'xx@qq.com&', '/']

  可以看到,注释内容并没有影响匹配结果。

  我们还可以将正则表达式写为多行,通过设置忽略多余的空白字符选项,可以将注释写为只是#开头,这种方式下,#的后面至行末都被判断为注释。

string='qq14717287xx@qq.com&10010/10086'
pattern=r'''\D+     #This is a comment
            .{2}    #This is a comment too
            \d+     #This is also a comment'''
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']
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值