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

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

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

字符:

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

  W 匹配非字母或数字或下划线或汉字
  s 匹配任意的空白符,相当于[  fv]

  S 匹配任何非空白字符,相当于[^ fv]
  d 匹配数字

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

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

() 表示分组

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

次数:

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

下划线

后面跟元字符的话去除元字符的特殊功能,
跟普通字符的话就会实现特殊功能
引用序号对应的字组所匹配的字符串,如:"(alex)(eric)com2",一个括号一个组,说明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, 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, 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("hw+", 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("aw+", 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("aw+",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("aw+", "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中 a 等都有一些特殊意思,举个例子
f=open('d:abc.txt','r')会报错,因为a有特殊含义,所以需要加 ,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+wd+','a2b3c4d5'))
#输出结果为[2b3,4d5]匹配的顺序是这样的,匹配到2b3后,再从c开始往后匹配,匹配到4d5
#正则表达式匹配的顺序没有匹配到的时候是按个往后找,一旦匹配到,把匹配到的拿走,从匹配后的往后找
print(re.findall('','a2b3c4d5'))
#注意看这句的输出结果为['', '', '', '', '', '', '', '', '']


#分割
origin = 'hello alex bcd abcd lge acd 19'
print(re.split('aw+',origin,1))
#输出结果为:['hello ', ' bcd abcd lge acd 19']
print(re.split('(aw+)',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()
#替换
三样东西有助于缓解生命的疲劳:希望、睡眠和微笑。---康德
原文地址:https://www.cnblogs.com/ronghe/p/8796102.html