Python之路【第二十一篇】:正则表达式

正则表达式用于进行字符匹配,在正则表达式中有普通字符和元字符两种字符

python中re模块提供了正则表达式相关操作

字符:

  . 匹配除换行符以外的任意字符
  \w 匹配字母或数字或下划线或汉字

  \W 匹配非字母或数字或下划线或汉字
  \s 匹配任意的空白符,相当于[  \t\n\r\f\v]

  \S 匹配任何非空白字符,相当于[^ \t\n\r\f\v]
  \d 匹配数字

  \D 匹配非数字,相当于[^0-9]
  \b 匹配单词的开始或结束
  ^ 匹配字符串的开始
  $ 匹配字符串的结束

[] 字符集,在字符集中,一般的元字符就是去意义了,但也有没有失去意义的;例如[bc],b或c;[a-z] ;[^1-9],非的作用,除了1-9;

() 表示分组

| 表示或的意思,如([*/]|\*\*)就表示乘除或者幂运算

次数:

  * 重复零次或更多次
  + 重复一次或更多次
  ? 重复零次或一次
  {n} 重复n次
  {n,} 重复n次或更多次
  {n,m} 重复n到m次

下划线 \

后面跟元字符的话去除元字符的特殊功能,
跟普通字符的话就会实现特殊功能
引用序号对应的字组所匹配的字符串,如:"(alex)(eric)com\2",一个括号一个组,说明com后面还有匹配一个eric

贪婪匹配与非贪婪匹配

比如说*重复前一个字符零次或更多次,贪婪匹配的话就是按照最大的来匹配

在*后面加上?就变成非贪婪匹配了

match

# match,从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None
 
 match(pattern, string, flags=0)
 # pattern: 正则模型
 # string : 要匹配的字符串
 # falgs  : 匹配模式
     X  VERBOSE     Ignore whitespace and comments for nicer looking RE's.
     I  IGNORECASE  Perform case-insensitive matching.
     M  MULTILINE   "^" matches the beginning of lines (after a newline)
                    as well as the string.
                    "$" matches the end of lines (before a newline) as well
                    as the end of the string.
     S  DOTALL      "." matches any character at all, including the newline.
 
     A  ASCII       For string patterns, make \w, \W, \b, \B, \d, \D
                    match the corresponding ASCII character categories
                    (rather than the whole Unicode categories, which is the
                    default).
                    For bytes patterns, this flag is the only available
                    behaviour and needn't be specified.
      
     L  LOCALE      Make \w, \W, \b, \B, dependent on the current locale.
     U  UNICODE     For compatibility only. Ignored for string patterns (it
                    is the default), and forbidden for bytes patterns.

代码示例

# 无分组
r = re.match("h\w+", origin)
print(r.group())     # 获取匹配到的所有结果
print(r.groups())    # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组结果

# 有分组
# 为何要有分组?提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来)

r = re.match("h(\w+).*(?P<name>\d)$", origin)
print(r.group())     # 获取匹配到的所有结果
print(r.groups())    # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组

search

# search,浏览整个字符串去匹配第一个,未匹配成功返回None
# search(pattern, string, flags=0)

代码示例

# 无分组
r = re.search("a\w+", origin)
print(r.group())     # 获取匹配到的所有结果
print(r.groups())    # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组结果

# 有分组
r = re.search("a(\w+).*(?P<name>\d)$", origin)
print(r.group())     # 获取匹配到的所有结果
print(r.groups())    # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组

findall

# findall,获取非重复的匹配列表;如果有一个组则以列表形式返回,且每一个匹配均是字符串;如果模型中有多个组,则以列表形式返回,且每一个匹配均是元祖;
# 空的匹配也会包含在结果中
#findall(pattern, string, flags=0)

代码示例

# 无分组
r = re.findall("a\w+",origin)
print(r)

# 有分组
origin = "hello alex bcd abcd lge acd 19"
r = re.findall("a((\w*)c)(d)", origin)
print(r)

sub

# sub,替换匹配成功的指定位置字符串
 
sub(pattern, repl, string, count=0, flags=0)
# pattern: 正则模型
# repl   : 要替换的字符串或可执行对象
# string : 要匹配的字符串
# count  : 指定匹配个数
# flags  : 匹配模式

代码示例

# 与分组无关

origin = "hello alex bcd alex lge alex acd 19"
r = re.sub("a\w+", "999", origin, 2)
print(r)

split

# split,根据正则匹配分割字符串
 
split(pattern, string, maxsplit=0, flags=0)
# pattern: 正则模型
# string : 要匹配的字符串
# maxsplit:指定分割个数
# flags  : 匹配模式

代码示例

# 无分组
origin = "hello alex bcd alex lge alex acd 19"
r = re.split("alex", origin, 1)
print(r)

# 有分组
        
origin = "hello alex bcd alex lge alex acd 19"
r1 = re.split("(alex)", origin, 1)
print(r1)
r2 = re.split("(al(ex))", origin, 1)
print(r2)

附加说明

re.match(规则,字符串,标志位),标志位是说明匹配的方式,re.I使匹配对大小写 不敏感,re.L做本地化识别匹配,re.M多行匹配,re.S使.匹配包含换行符在内的所有字符

re.search(规则,字符串,标志位),标志位是说明匹配的方式,re.I使匹配对大小写不敏感,re.L做本地化识别匹配,re.M多行匹配,re.S使.匹配包含换行符在内的所有字符

match和search匹配成功之后会返回一个对象,需要调用相应的方法来进行输出:group()返回匹配的字符串,start()返回匹配开始的位置,end()返回匹配结束的位置,span()返回一个元组包含(开始,结束)的位置
group()默认参数为0,group(n),返回组号为n所匹配的字符串,group(n,m)返回组号为n,m所匹配的字符串

sub(规则,新的字符串,旧的字符串,max=0)用于替换,max用于规定替换几个,如果不加max最后面这个参数,返回时会返回替换好的字符串和一个数字,表示替换了几次

compile,把象,可以把那些经常需要匹配的表达式编译成正则表达式对象,这样可以提高一定的效率

在组的前后均有限制条件的话,用于非贪婪匹配的?就不起作用了?有一个正则表达式,如:a(\d+)b,字符串为a23b,使用findall结果是23,使用search结果是a23b,并且此时使用?,也不会变为非贪婪模式

在python中\n \r \a \b等都有一些特殊意思,举个例子
f=open('d:\abc.txt','r')会报错,因为\a有特殊含义,所以需要加\r,f=open(r'd:\abc.txt','r')
在字符串前面加r就表示原生字符串
在很多情况下,使用findall函数会优先获取组里面的内容,这时候在前面加?:就可以把这种权限取消,例如:'www.(?:baidu).com',这样就会匹配出www.baidu.com而不是只匹配出baidu

常用正则表达式

IP:
^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$
手机号:
^1[3|4|5|8][0-9]\d{8}$
邮箱:
[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+

 随堂笔记

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import re

#使用模块要看模块的源文件
#默认情况下是贪婪的
#最常用的re函数,match与findall最常用
# re.match()        匹配开头
# re.search()       浏览全部字符串,匹配第一个符合规则的字符串
# re.findall()      将匹配到的所有内容放入一个列表中
# #re.finditer()    与findall的区别类似于range与xrange分区别,只有迭代才能输出
# re.split()
# re.sub()

#match,search,findall这些方法概括起来有两种匹配方式:简单匹配和分组匹配
#match,search会返回一个对象,对象里有多种方法,这些对象里最最基本的有group(),groups(),groupdict()这三个方法
#match,search,findall里面都有三个参数,正则表达式,源字符串,标志位
#为何要有分组
#分组就是取已经匹配到的内容里取取值,有几个括号就取几次,不管嵌套有多深
#简单匹配

orign = 'hello alex bcd alev lge alec acd 19'
r = re.match('(h)(\w+)',orign)
print(r.group()) #获取匹配到的所有结果
print(r.groups())#获取模型中匹配到的分组结果

r = re.match('(?P<n1>h)(?P<n2>\w+)',orign)
print(r.groupdict())#获取模型中匹配到的分组中所有执行了key的组
#?P<键>固定写法

#search与match一样,只不过一个匹配开头,一个匹配第一个
orign = 'hello alex bcd alev lge alec acd 19'
r = re.search('(a)(\w+)',orign)
print(r.group())
print(r.groups())

r = re.search('(?P<n1>a)(?P<n2>\w+)',orign)
print(r.groupdict())

print(re.findall('\d+\w\d+','a2b3c4d5'))
#输出结果为[2b3,4d5]匹配的顺序是这样的,匹配到2b3后,再从c开始往后匹配,匹配到4d5
#正则表达式匹配的顺序没有匹配到的时候是按个往后找,一旦匹配到,把匹配到的拿走,从匹配后的往后找
print(re.findall('','a2b3c4d5'))
#注意看这句的输出结果为['', '', '', '', '', '', '', '', '']


#分割
origin = 'hello alex bcd abcd lge acd 19'
print(re.split('a\w+',origin,1))
#输出结果为:['hello ', ' bcd abcd lge acd 19']
print(re.split('(a\w+)',origin,1))
#输出结果为:['hello ', 'alex', ' bcd abcd lge acd 19']
print(re.split('a(\w+)',origin,1))
#输出结果为:['hello ', 'lex', ' bcd abcd lge acd 19']

#1-2*((60-30+(-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))
origin = '1-2*((60-30+(-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'
print(re.findall('\([^()]+\)',origin))
#可以取得内层括号
#输出结果为:['(-40.0/5)', '(9-2*5/3+7/3*99/4*2998+10*568/14)', '(-4*3)', '(16-3*2)']

#利用re.split() 写计算器

re.sub()
#替换

 

posted @ 2018-04-11 15:41  RongHe  阅读(179)  评论(0编辑  收藏  举报