(一)re模块

re模块是python中的正则表达模块,其使用格式为:

(1)match

  1. re.match(正则表达式, 带匹配字符串,选项)
  • re.match尝试从字符串的起始位置匹配一个模式,如果不是起止位置匹配成功的话,match()就返回none.
  • re.match主要用于正则匹配检查,如果带匹配字符串能够匹配正则表达式,则match方法返回对象,否则返回None
  • 采用从左往右的顺序逐项进行比较
  • flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等

具体标志位可以使用的修饰符如下(多个标志位可以通过按位OR(|)来指定,例如:re.I | re.M被设置成I和M标志)

修饰符 描述
re.I 使匹配对大小写不敏感
re.L 做本地化识别(local-aware)匹配
re.M 多行匹配,影响^和$,否则只单行
re.S 是.匹配包括换行在内的所有字符
re.U 根据Unicode字符集解析字符,这个标志影响\w \W \B \b
re.X 该标志给与你更灵活的格式以便你讲正则表达式写得更容易理解

(2)group()方法

用来返回字符串的匹配部分

(二)正则表达式中的单字符匹配

(1)单字符匹配的元字符

字符 描述
. 匹配除了”\n”之外的任意单个字符
\d 匹配0到9之间的一个数字,等价于[0-9]
\D 匹配一个非数字字符,等价于[1]
\s 匹配任何空白字符,如空格、制表符”\t”、换行符”\n”等
\S 匹配任意非空白字符
\w 匹配任意单词字符(包括下划线),如:a-z,A-Z,0-9
\W 匹配任意非单词字符,相当于[^a-zA-Z0-9_]
[] 匹配[]中列举的字符
^ 取反

例如:

  1. #!/home/python/bin/bin/python3
  2. import re
  3. rs = re.match(".","a")
  4. print(rs.group())
  5. rs = re.match(".","1")
  6. print(rs.group())
  7. rs = re.match("...","abc")
  8. print(rs.group())
  9. rs = re.match(".","\n")
  10. print(rs)
  11. #\s
  12. rs = re.match("\s","\t")
  13. print(rs)
  14. rs = re.match("\s","\n")
  15. print(rs)
  16. rs = re.match("\s"," ")
  17. print(rs)
  18. #\S
  19. rs = re.match("\S","\t")
  20. print(rs)
  21. rs = re.match("\S","abc")
  22. print(rs)
  23. #\w
  24. rs = re.match("\w","a")
  25. print(rs)
  26. rs = re.match("\w","A")
  27. print(rs)
  28. rs = re.match("\w","1")
  29. print(rs)
  30. rs = re.match("\w","_")
  31. print(rs)
  32. rs = re.match("\w","中")
  33. print(rs)
  34. rs = re.match("\w","*") #非单词字符
  35. print(rs)
  36. #[]
  37. rs = re.match("[Hh]","hello")
  38. print(rs)
  39. rs = re.match("[Hh]","Hello")
  40. print(rs)
  41. rs = re.match("[0123456789]","32")
  42. print(rs)
  43. #等价
  44. rs = re.match("[0-9]","3")
  45. print(rs)

运行结果为:

  1. a
  2. 1
  3. abc
  4. None
  5. <re.Match object; span=(0, 1), match='\t'>
  6. <re.Match object; span=(0, 1), match='\n'>
  7. <re.Match object; span=(0, 1), match=' '>
  8. None
  9. <re.Match object; span=(0, 1), match='a'>
  10. <re.Match object; span=(0, 1), match='a'>
  11. <re.Match object; span=(0, 1), match='A'>
  12. <re.Match object; span=(0, 1), match='1'>
  13. <re.Match object; span=(0, 1), match='_'>
  14. <re.Match object; span=(0, 1), match='中'>
  15. None
  16. <re.Match object; span=(0, 1), match='h'>
  17. <re.Match object; span=(0, 1), match='H'>
  18. <re.Match object; span=(0, 1), match='3'>
  19. <re.Match object; span=(0, 1), match='3'>

(2)数量表示的元字符

字符 描述
* 一个字符可以出现任意次,也可以一次都不出现,即从0次到无穷大次
+ 一个字符至少出现一次
? 一个字符至多出现一次
{m} 一个字符出现m次
{m,} 一个字符至少出现m次
{,n} 一个字符至多出现n次
{m,n} 一个字符出现m到n次

例如:

  1. #!/home/python/bin/bin/python3
  2. import re
  3. #数量表示方法:
  4. #*任意次
  5. rs = re.match("1\d*","1234567")
  6. print(rs.group())
  7. rs = re.match("1\d*","1234567abc")
  8. print(rs.group())
  9. #+至少出现一次
  10. rs = re.match("\d+","abc")
  11. print(rs)
  12. rs = re.match("\d+","1abc")
  13. print(rs)
  14. rs = re.match("\d+","123345abc")
  15. print(rs)
  16. #?至多1次(0次或者1次)
  17. rs = re.match("\d?","abc")
  18. print(rs)
  19. rs = re.match("\d?","123abc")
  20. print(rs)
  21. #{m}固定次数
  22. rs = re.match("\d{3}","123abc")
  23. print(rs)
  24. #{m,}
  25. rs = re.match("\d{1,}","123467abc")#等价于+至少一次
  26. print(rs)
  27. #{m,n}
  28. rs = re.match("\d{0,1}","abc") #等价于?至多一次
  29. print(rs)
  30. #匹配11位的手机号
  31. #11位,第一位1,第二位3,5,7,8 第3位到第11为0到9的数字
  32. rs = re.match("1[3578]\d{9}","13623198765")
  33. print(rs)
  34. rs = re.match("1[3578]\d{9}","14623198765")#非法手机号
  35. print(rs)
  36. rs = re.match("1[3578]\d{9}","13623198765abc")#非法手机号
  37. print(rs)

运行可得:

  1. 1234567
  2. 1234567
  3. None
  4. <re.Match object; span=(0, 1), match='1'>
  5. <re.Match object; span=(0, 6), match='123345'>
  6. <re.Match object; span=(0, 0), match=''>
  7. <re.Match object; span=(0, 1), match='1'>
  8. <re.Match object; span=(0, 3), match='123'>
  9. <re.Match object; span=(0, 6), match='123467'>
  10. <re.Match object; span=(0, 0), match=''>
  11. <re.Match object; span=(0, 11), match='13623198765'>
  12. None
  13. <re.Match object; span=(0, 11), match='13623198765'>

(3)字符串和单词边界的元字符

字符 描述
^ 用于匹配一个字符串的开头
$ 用于匹配一个字符串的结尾
\b 用于匹配单词的边界
\B 用于匹配费单词的边界

附注:\b匹配这样的位置:它的前一个字符和后一个字符不全是(一个是,一个不是或不存在)\w(匹配字母或数字或下划线)

例如:

  1. #!/home/python/bin/bin/python3
  2. import re
  3. #转义字符处理
  4. str1 = "hello\\world"
  5. print(str1)
  6. str2 = "hello\\\\world"
  7. print(str2)
  8. str3 = r"hello\\world"#原生字符串
  9. print(str3)
  10. rs = re.match("\w{5}\\\\\\\\\w{5}",str3)
  11. print(rs)
  12. rs = re.match(r"\w{5}\\\\\w{5}",str3)
  13. print(rs)
  14. #边界表示
  15. #$字符串结尾
  16. rs = re.match("1[3578]\d{9}$","13623456767")
  17. print(rs.group())
  18. rs = re.match("1[3578]\d{9}$","13623456767abc")
  19. print(rs)
  20. '''
  21. #邮箱匹配
  22. '''
  23. rs = re.match("\w{3,10}@163\.com$","hello_124@163.com")
  24. print(rs)
  25. rs = re.match("\w{3,10}@163.com$","he@163.com")
  26. print(rs)
  27. rs = re.match("\w{3,10}@163\.com$","hello_124@163mcom")
  28. print(rs)
  29. #\b 单词边界
  30. rs = re.match(r".*\bpython\b","hi python hello")
  31. print(rs)
  32. #\B非单词边界
  33. rs = re.match(r".*\Bth\B","hi python hello")
  34. print(rs)

运行结果为:

  1. hello\world
  2. hello\\world
  3. hello\\world
  4. <re.Match object; span=(0, 12), match='hello\\\\world'>
  5. <re.Match object; span=(0, 12), match='hello\\\\world'>
  6. 13623456767
  7. None
  8. <re.Match object; span=(0, 17), match='hello_124@163.com'>
  9. None
  10. <re.Match object; span=(0, 9), match='hi python'>
  11. <re.Match object; span=(0, 7), match='hi pyth'>
  12. [python@izbp1f14rcq86rw425zgewz lesson8]$ vim test2.py
  13. [python@izbp1f14rcq86rw425zgewz lesson8]$ ./test2.py
  14. hello\world
  15. hello\\world
  16. hello\\world
  17. <re.Match object; span=(0, 12), match='hello\\\\world'>
  18. <re.Match object; span=(0, 12), match='hello\\\\world'>
  19. 13623456767
  20. None
  21. <re.Match object; span=(0, 17), match='hello_124@163.com'>
  22. None
  23. None
  24. <re.Match object; span=(0, 9), match='hi python'>
  25. <re.Match object; span=(0, 7), match='hi pyth'>

(4)分组匹配元字符

字符 描述
表示或的意思,匹配
() 将括号中字符作为一个分组
\NUM 配合分组()使用,引用分组NUM(NUM表示分组的编号)对应的匹配规则
(?P) 给分组起别名
(?P=NAME) 应用指定别名的分组匹配到的字符串
(?:pattern) 匹配pattern,但是并不保存在分组结果中,也就是说这是一个非获取匹配,以后不能以指定组的形式去调用。这种形式在使用

例如:

  1. #!/home/python/bin/bin/python3
  2. import re
  3. #()分组
  4. rs = re.match("\w{3,10}@(163|qq|outlook)\.com$","hello@163.com")
  5. print(rs)
  6. rs = re.match("\w{3,10}@(163|qq|outlook)\.com$","1234567@qq.com")
  7. print(rs)
  8. #\num
  9. html_str = "<head><title>python</title></head>"
  10. rs = re.match(r"<.+><.+>.+</.+></.+>",html_str)
  11. print(rs)
  12. html_str2 = "<head><title>python</head></title>"
  13. rs = re.match(r"<.+><.+>.+</.+></.+>",html_str2)
  14. print(rs)
  15. rs = re.match(r"<(.+)><(.+)>.+</\2></\1>",html_str)
  16. print(rs)
  17. rs = re.match(r"<(.+)><(.+)>.+</\2></\1>",html_str2)
  18. print(rs)
  19. rs = re.match(r"<(?P<g1>.+)><(?P<g2>.+)>.+</(?P=g2)></(?P=g1)>",html_str)
  20. print(rs)

运行可得:

  1. <re.Match object; span=(0, 13), match='hello@163.com'>
  2. <re.Match object; span=(0, 14), match='1234567@qq.com'>
  3. <re.Match object; span=(0, 34), match='<head><title>python</title></head>'>
  4. <re.Match object; span=(0, 34), match='<head><title>python</head></title>'>
  5. <re.Match object; span=(0, 34), match='<head><title>python</title></head>'>
  6. None
  7. <re.Match object; span=(0, 34), match='<head><title>python</title></head>'>

关于并不保存在分组结果中的分组的例子:

  1. #!/home/python/bin/bin/python3
  2. import re
  3. #匹配industry或者industries
  4. s="industry"
  5. rs=re.match("industr(?:y|ies)",s)
  6. print(rs)

运行可得:

  1. <re.Match object; span=(0, 8), match='industry'>

(5)前向界定与前向非界定,后向界定与后向非界定

字符 描述
(?=pattern) look ahead positive assert-向前查找肯定断言,即要求满足查找要求的字符串的后面必须有匹配pattern的字符串。
(?!pattern) look ahead negative assert-向前查找否定断言,即要求满足查找条件的字符串紧跟字符必须不能匹配pattern
(?<=pattern) look behind positive assert-向后查找肯定断言,即要求满足查找条件的字符串的前面必须有匹配pattern的字符串。
(?<!pattern) look behind negative assert-向后查找否定断言,即要求满足查找条件的字符串的前面的字符必须不能匹配pattern。

这里举例如下:

  1. #查找windows,要求windows后面的字符串是95或者98或者NT或者2000
  2. rs = re.match("windows(?=95|98|NT|2000)","windows2000")
  3. print(rs)
  4. #查找windows,要求windows后面的字符串不能是95或者98或者NT或者2000
  5. rs=re.match("windows(?!95|98|NT|2000)","windows3.1")
  6. print(rs)
  7. #查找windows,要求windows前面的字符串是2000
  8. rs=re.search("(?<=2000)windows", "882000windows")
  9. print(rs)
  10. #查找windows,要求windows前面的字符串不能是2000
  11. rs=re.search("(?<!2000)windows","abcwindows")
  12. print(rs)

运行结果为:

  1. <re.Match object; span=(0, 7), match='windows'>
  2. <re.Match object; span=(0, 7), match='windows'>
  3. <re.Match object; span=(6, 13), match='windows'>
  4. <re.Match object; span=(3, 10), match='windows'>

注意:后向查找(look behind assert)要求pattern的宽度固定,因此以下的表达式非法的:

  1. #正则宽度为2、3、4,不固定,错误
  2. rs=re.search("(?<=2000|NT|985)windows", "882000windows")

运行会报错

  1. raise error("look-behind requires fixed-width pattern")

而以下表达就是合法的,正确的

  1. rs = re.search('(?<=2000|3000|4000)windows','2000windows')

运行可得:

  1. <re.Match object; span=(4, 11), match='windows'>

(6)正则表达式的运算符优先级别

正则表达式从左到右进行运算,并遵循优先级顺序,这与算术表达式非常类似。
相同有衔接的从左到右进行运算,不同优先级的运算先高后低。下表从最高到最低说明了各种正则表达式运算符的优先级顺序。

运算符 描述符
(),(?:),(?=),[] 圆括号或方括号
*,+,?,{n},{n,m} 限定符
^,$,\任何元字符,任何字符 定位点和序列(即:位置和顺序)
| 替换,“或”操作

(三)re模块基本函数

(1)re.search方法

re.search扫描真个字符串并返回第一个成功的匹配,而re.match必须从开头开始匹配,这点有着显著不同。
函数语法为:

  1. re.search(patern, string, flags=0)
  • pattern 正则表达式
  • string 要匹配的字符串
  • flags 标志位,控制正则表达式的匹配方式

若匹配成功,则返回一个匹配的对象,否则返回None.
我们可以使用group(num)或者groups()匹配对象函数来获取匹配表达式。

匹配对象方法 描述
group(num=0) 匹配的整个表达式的字符串,group()可以一次输入多个组号,在这种情况下它将返回一个包含那些组对应的元组。
groups() 返回一个包含所有小组字符的元组,从1到所含小组号

实例如下:

  1. #!/home/python/bin/bin/python3
  2. import re
  3. #搜索满足条件的正则表达式
  4. rs = re.search('\d\.\S+','1.Sam 2.Smith 3.John 4.Black')
  5. #打印结果
  6. print(rs)
  7. print(rs.group(0))
  8. print("--------------------------")
  9. #搜索满足条件的正则表达式,表达式中有三个分组
  10. rs = re.search('(\d\.\w+\s+)(\d\.\w+\s+)(.*)','1.Sam 2.Smith 3.John 4.Black')
  11. print(rs)
  12. #以每个结果一个分组元素的心事展示结果
  13. print(rs.groups())
  14. #以合并显示的形式展示结果
  15. print(rs.group(0))
  16. #展示第一个分组的匹配结果
  17. print(rs.group(1))
  18. #展示第二个分组的匹配结果
  19. print(rs.group(2))
  20. #展示第三个分组的匹配结果
  21. print(rs.group(3))

运行结果为:

  1. <re.Match object; span=(0, 5), match='1.Sam'>
  2. 1.Sam
  3. --------------------------
  4. <re.Match object; span=(0, 28), match='1.Sam 2.Smith 3.John 4.Black'>
  5. ('1.Sam ', '2.Smith ', '3.John 4.Black')
  6. 1.Sam 2.Smith 3.John 4.Black
  7. 1.Sam
  8. 2.Smith
  9. 3.John 4.Black

re.match与re.search的区别

re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败。函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

(2)findall

findall的作用是在目标字符串中查找符合正则规则的结果,并把结果放到一个列表中。如果没有找到匹配的字符串,则返回空列表。

同match和search只匹配一次不同,findall是匹配满足正则表达式的每一个字符串,并把每个结果放入列表中。

其格式如下:

举例如下:

  1. #!/home/python/bin/bin/python3
  2. s='<param name="File" value="${catalina.home}/logs/store/application.log" />'
  3. rs=re.findall(r'\b.*?=',s)
  4. print(rs)
  5. rs=re.findall(r'\bparam\b',s)
  6. print(rs)

运行结果为:

  1. ['param name=', 'File" value=']
  2. ['param']

可见,所有满足条件的记录都被放入了列表中。

(3)finditer

和findall类似,在字符串中找到正则表达式所匹配的所有子串,并把他们作为一个迭代器返回
格式:

  1. rd.finditer(pattern, string, flags=0)

参数:

参数 描述
string 要匹配的字符串
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等

例如:

  1. #以下代码试图把字符串中的每个单词单独取出来,放到一个装饰器对象的迭代器中
  2. rs=re.finditer(r'\b\w+?\b','<param name="File" value="${catalina.home}/logs/store/application.log')
  3. #打印出迭代器中的每个对象
  4. for item in rs:
  5. print(item)

运行结果为:

  1. <re.Match object; span=(1, 6), match='param'>
  2. <re.Match object; span=(7, 11), match='name'>
  3. <re.Match object; span=(13, 17), match='File'>
  4. <re.Match object; span=(19, 24), match='value'>
  5. <re.Match object; span=(28, 36), match='catalina'>
  6. <re.Match object; span=(37, 41), match='home'>
  7. <re.Match object; span=(43, 47), match='logs'>
  8. <re.Match object; span=(48, 53), match='store'>
  9. <re.Match object; span=(54, 65), match='application'>
  10. <re.Match object; span=(66, 69), match='log'>

(4)split

split方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:

  1. re.split(pattern,string[,maxsplit=0, flags=0])

参数:

参数 描述
pattern 匹配的正则表达式
string 要匹配的字符串
maxsplit 分割次数,maxsplit=1分割一次,默认为0,不限制次数
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等

例如:

  1. s="Long,Long,ago,there,is,a, very, good,,position"
  2. #指定按,+\W*方式去对字符串进行分割
  3. rs=re.split(",+\W*",s)
  4. print(rs)

运行结果为:

  1. ['Long', 'Long', 'ago', 'there', 'is', 'a', 'very', 'good', 'position']

(5)sub —检索和替换

Python中的re模块提供了re.sub用于替换字符串中的匹配项
语法:

  1. re.sub(pattern, repl, string, count=0 ,falgs=0)

参数:

  • pattern:正则表达式
  • repl:字符串或者函数,用于替换掉原始字符串中的字符
  • string:原始字符串,其中部分字符要被替换掉
  • count:模式匹配后替换的最大次数,默认0表示替换所有的匹配
  1. #!/home/python/bin/bin/python3
  2. import re
  3. phone = "2018-109-109 # 这是一个国外电话号码"
  4. #将注释替换掉
  5. num = re.sub('#.*$',"",phone)
  6. print("The phone number is:{}".format(num))
  7. #将号码中的-替换掉
  8. num=re.sub(r'\D',"",num)
  9. print("The phone number is:{}".format(num))

运行可得:

  1. The phone number is:2018-109-109
  2. The phone number is:2018109109

re.sub方法允许把函数作为参数传入repl位置(第二个参数),这个时候,sub方法将把同pattern匹配的每一个match对象作为参数传递给repl位置的函数,例如:

  1. #!/home/python/bin/bin/python3
  2. import re
  3. #将字符数字乘以2,返回字符型数字
  4. def double_number(matched):
  5. value = int(matched.group('value'))
  6. return str(value*2)
  7. number = '12abcU890KK972L1'
  8. #对指定表达式进行正则搜索,找出每一个数字,并将数字乘以2,然后返回
  9. rs = re.sub('(?P<value>\d+)',double_number, number)
  10. print(rs)

运行结果为:

  1. 24abcU1780KK1944L2

(四)贪婪模式与非贪婪模式

(1)介绍

  • 贪婪模式
    正则表达式引擎默认是贪婪模式,尽可能多的匹配字符

  • 非贪婪模式

    • 与贪婪模式相反,尽可能少的匹配字符
    • 在表示数量的“*”,“?”,“+”,“{m,n}”符号后面加上?,使得贪婪变成非贪婪

(2)举例

在贪婪模式下:

  1. #!/home/python/bin/bin/python3
  2. import re
  3. rs = re.findall(r"hello\d*","hello12345")
  4. print(rs)
  5. rs = re.findall(r"hello\d+","hello12345")
  6. print(rs)
  7. rs = re.findall(r"hello\d?","hello12345")
  8. print(rs)
  9. rs = re.findall(r"hello\d{2,}","hello12345")
  10. print(rs)
  11. rs = re.findall(r"hello\d{1,3}","hello12345")
  12. print(rs)

运行结果为:

  1. ['hello12345']
  2. ['hello12345']
  3. ['hello1']
  4. ['hello12345']
  5. ['hello123']

而在非贪婪模式下

  1. #!/home/python/bin/bin/python3
  2. import re
  3. #在数量*,?,+,{m,n}后面加?则为非贪婪模式
  4. rs = re.findall(r"hello\d*?","hello12345")
  5. print(rs)
  6. rs = re.findall(r"hello\d+?","hello12345")
  7. print(rs)
  8. rs = re.findall(r"hello\d??","hello12345")
  9. print(rs)
  10. rs = re.findall(r"hello\d{2,}?","hello12345")
  11. print(rs)
  12. rs = re.findall(r"hello\d{1,3}?","hello12345")
  13. print(rs)

运行结果为:

  1. ['hello']
  2. ['hello1']
  3. ['hello']
  4. ['hello12']
  5. ['hello1']

由此可以见,在非贪婪模式下,实现了字符的最少匹配,能少匹配尽量少匹配,皆取下限


  1. 0-9 ↩︎