Python 模式匹配和正则表达式

Python 模式匹配和正则表达式

7.2 用正则表达式查找文本模式

  • '/d' 正则的数字字符

7.2.1 创建正则表达式对象

  1. re模块
import re   #'re'正则表达式函数
re.compile()  #'compile'方法,正则表达式匹配,返回regex对象

7.2.2 匹配Regrex对象

phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')   #'r',‘\’就是反斜杠,不是转义字符标识,'r'代表符号本来的意思
#print(r'That is job\'s cat.') => That is job\'s cat'
mo = phoneNumRegex.search('My number is 456-621-3254.')
print('phone number is ' + mo.group())

>>>phone number is 456-621-3254

7.3 用正则表达式匹配更多模式

7.3.0 不匹配时错误显示

batRegex = re.compile(r'Bat(wo)+man')
mo1 = batRegex.search('The Adventures of Batman')   #在输入中正则未匹配到字符
mo1.group()


AttributeError: 'NoneType' object has no attribute 'group'

7.3.1 利用括号分组

phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)') 
mo = phoneNumRegex.search('My number is 456-621-3254.')
mo.group(1)   #分组1匹配到的字符串
>>>'456'
mo.group(2)   #分组2匹配到的字符串(第二个括号内的正则规则)
>>>'621-3254'
mo.group(0)
>>>456-621-3254

7.3.2 用管道匹配多个分组('|')

heroRegex = re.compile(r'Batman|Tina Fey')
mo1 = heroRegex.search('Batman and Tina Fey.')
mo1.group()
>>>'Batman'

heroRegex = re.compile(r'Batman|Tina Fey')
mo1 = heroRegex.search('Tina Fey and Batman y.')
mo1.group()
>>>'Tina Fey'

7.3.3 用问号实现可选匹配('?'零次或一次)

batRegex = re.compile(r'Bat(wo)?man')
mo1 = batRegex.search('The Adventures of Batman')
mo1.group()
>>>'Batman'

mo2 = batRegex.search('The Adventures of Batwoman')
mo2.group()
>>>'Batwoman'

7.3.4 用星号匹配零次或多次('*'零次或多次)

batRegex = re.compile(r'Bat(wo)*man')      #零次或多次
mo1 = batRegex.search('The Adventures of Batman')  #(wo)匹配零次
mo1.group()
>>>'Batman'

mo2 = batRegex.search('The Adventures of Batwowowowoman')  #(wo)匹配多次
mo2.group()
>>>'Batwowowowoman'

7.3.5 用加号匹配一次或多次('+'一次或多次)

batRegex = re.compile(r'Bat(wo)+man')
mo1 = batRegex.search('The Adventures of Batwoman')
mo1.group()
>>>'Batwoman'

mo2 = batRegex.search('The Adventures of Batwowowoman')
mo2.group()
>>>'Batwowowoman'

7.3.6 用花括号匹配特定次数('{ }'特定次数)

(ha){3}    #匹配字符串'hahaha'
(ha){1,3}  #匹配字符串'ha|haha|hahaha'其中一种情况
(ha){,5}   #匹配字符串'ha',0到5次
(ha){3,}   #匹配3次或更多次实例

haRegex = re.compile(r'(Ha){3}')
mo1 = haRegex.search('HaHaHa')
mo1.group()
>>>'HaHaHa'

7.4 贪婪和非贪婪匹配

Python的正则表达式默认是'贪婪模式'

  • 贪婪模式:尽可能匹配最长的字符串(默认模式)
  • 非贪婪模式: 尽可能匹配最短的字符串('{ }?')
greedyHaRegex = re.compile(r'(Ha){3,5}')     #默认模式‘贪婪’
mo1 = greedyHaRegex.search('HaHaHaHaHa')
mo1.group()
>>>'HaHaHaHaHa'

greedyHaRegex = re.compile(r'(Ha){3,5}?')    #非贪婪匹配
mo2 = greedyHaRegex.search('HaHaHaHaHa')
mo2.group()
>>>'HaHaHa'

7.5 findall()方法

  • search(): 只包含第一次出现的匹配
  • findall(): 字符串中匹配的所有
# search()只包含第一次出现的匹配
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
mo = phoneNumRegex.search('Cell: 415-5555-9999 Work: 212-555-0000')
mo.group()
>>>'212-555-0000'

# findall()查找字符串中的所有匹配,
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
phoneNumRegex.findall('Cell: 415-555-9999 Work: 212-555-0000')
>>>['415-555-9999', '212-555-0000']   #无分组时,返回list类型的所有匹配

# findall()有分组时
phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d)-(\d\d\d\d)')
phoneNumRegex.findall('Cell: 415-555-9999 Work: 212-555-0000')
>>>[('415', '555', '9999'), ('212', '555', '0000')]  #有分组时,返回list内的tuple类型

7.6 字符分类

缩写字符分类 表示
\D 除0到9的数字以外的任何字符
\d 0到9的任何数字
\w 任何字母,数字,下划线字符(认为是匹配'单词')
\W 除字母,数字,下划线以外的任何字符
\s 空格,制表符,换行符(认为是匹配‘空格’字符)
\S 除空格,制表符,换行符以外额任何字符

7.6.1 使用示例

xmasRegex = re.compile(r'\d+\s\w+')   #匹配的文本有一个或多个数字(\d+),接下来是空格(\s),接下来是一个或多个字母,数字,下划线字符(\w+)
xmasRegex.findall('12 drummers, 11 pipers, 10 lords')
>>>['12 drummers', '11 pipers', '10 lords']

7.7 建立自己的字符分类

字符分类

  • [a-zA-Z0-9] 匹配所有小写字母,大写字母和数字

  • [^a-zA-Z] 匹配除大小写字母外其他字符

    vowlRegex = re.compile(r'[a-zA-Z0-9]')  #匹配大小写字母和数字
    vowlRegex.findall('This year is 2020')
    >>>['T', 'h', 'i', 's', 'y', 'e', 'a', 'r', 'i', 's', '2', '0', '2', '0']
    
    vowlRegex = re.compile(r'[0-9]')    #只匹配数字
    vowlRegex.findall('This year is 2020')
    >>>['2', '0', '2', '0']
    
    vowlRegex = re.compile(r'[^0-9]')   #除数字外的其他字符
    vowlRegex.findall('This year is 2020')
    >>>['T', 'h', 'i', 's', ' ', 'y', 'e', 'a', 'r', ' ', 'i', 's', ' ']
    

7.8 ''^'和'$'

  • ^ 匹配以正则某模式开始
  • $ 字符串以正则某模式结束

7.8.1 示例

1 以某字符开头的内容
beginsWithHello = re.compile(r'^Hello')
beginsWithHello.search('Hello World')
>>><_sre.SRE_Match object; span=(0, 5), match='Hello'>

2 以数字结尾的字符串
endsWithNumber = re.compile(r'\d+$')   #'\d+$'以数字结尾的一个或多个数字
endsWithNumber.search('Your number is 42')
>>><_sre.SRE_Match object; span=(15, 17), match='42'>

3 从开头到结尾全是数字的字符串
endsWithNumber = re.compile(r'^\d+$')  #'^\d+$'开头到结尾全是数字的字符串
endsWithNumber.search('1234567890')
>>><_sre.SRE_Match object; span=(0, 10), match='1234567890'>

7.9 通配字符('.'匹配一个字符)

它匹配除了换行之外的所有字符

atRegex = re.compile(r'.at')
atRegex.findall('The cat in the hat sat on the flat mat.')
>>>['cat', 'hat', 'sat', 'lat', 'mat']

7.9.1 匹配所有字符('.*'任意字符)

它匹配除换行外的所有字符

nameRegex = re.compile(r'First Name:(.*) Last Name:(.*)')   #'.*'表示匹配任意字符
mo = nameRegex.search('First Name:AL Last Name:Sweigart')
mo.group(1)  #因为出现'()',所以通过'group()'来进行匹配
>>>'AL'
mo.group(2)
>>>'Sweigart'
  1. 贪婪模式: .*

  2. nongreedyRegex = re.compile(r'<.*>')
    mo = nongreedyRegex.search('<To serve man> for dinner.>')
    mo.group()
    >>>'<To serve man> for dinner.>'
    
  3. 非贪婪模式: .*?

  4. nongreedyRegex = re.compile(r'<.*?>')
    mo = nongreedyRegex.search('<To serve man> for dinner.>')
    mo.group()
    >>>'<To serve man>'
    

7.9.2 're.DOTALL'匹配换行

noNewlineRegex = re.compile('.*')  
noNewlineRegex.search('Serve the public trust. \nProtect the innocent.').group()  #换行符('\n')后的内容无法匹配
>>>'Serve the public trust. '   

noNewlineRegex = re.compile('.*', re.DOTALL)  
noNewlineRegex.search('Serve the public trust. \nProtect the innocent.').group() 
>>>'Serve the public trust. \nProtect the innocent.'

7.10 正则表达式符号复习

  • ? 匹配零次或一次前面的分组
  • * 匹配零次或多次前面的分组
  • **+** 匹配一次或多次前面的分组
  • **{n}** 匹配n次前面的分组
  • **{n,}** 匹配n次或更多前面的分组
  • *{n,m}* 匹配至少n次,至多m次前面的分组
  • **{n,m}?**或*或+?对前面的分组进行非贪婪匹配
  • ^spam 字符串必须以spam开头
  • spam$ 字符串必须以spam结束
  • *.* 匹配所有字符,除换行符以外
  • *[abc]* 匹配方括号内的任意字符(比如a,b或c)
  • [^abc] 匹配不在方括号内的任意字符

7.11 不区分大小写的匹配(re.I == re.IGNORECASE)

robocop = re.compile(r'robocop',re.I)  #第二参数're.I'不区分大小写
robocop.search('RoboCop is part man').group()
>>>'RoboCop'
robocop.search('ROBOCOP protects the innocent.').group()
>>>'ROBOCOP'
robocop.search('roboCop so mush').group()
>>>'roboCop'

7.12 用sub()方法替换字符串

Regex对象的sub()需要传入两个参数,第一个参数要替换的字符串,第二个是用于匹配的内容

namesRegex = re.compile(r'Agent \w+')  
namesRegex.sub('CENSORED', 'Agent Alice gave the secret documents to Agent Bob.') #用'CENSORED'替换正则匹配字符串
>>>'CENSORED gave the secret documents to CENSORED.'

namesRegex = re.compile(r'Agent (\w)\w*')
namesRegex.sub(r'\1****', 'Agent Alice told Agent Carol that Agent Eva knew')  #'\1'分组1'(\w)''
>>>'A**** told C**** that E**** knew'

7.12.1 markdown需要转义的字符

\\ 反斜杠
\` 反引号
\* 星号
\_ 下划线
\{\} 大括号
\[\] 中括号
\(\) 小括号
\# 井号
\+ 加号
\- 减号
\. 英文句号
\! 感叹号

7.13 管理复杂的正则表达式

7.13.1 复杂的正则表达式

#复杂的正则表达式
phoneRegex = re.compile(r'((\d{3}|\(\d{3}\))?(\s|-|\.)?\d{3}(\s|-|\.)\d{4}(\s*(ext|x|ext.)\s*\d{2,5})?)')

7.13.2 简洁的正则表达式

phoneRegex = re.compile(r'''(
(\d{3}|\(\d{3}\))?    #区号
(\s|-|\.)?            #分隔符
\d{3}                 #3位数字
(\s|-|\.)             #分隔符
\d{4}                 #4位数字
(\s*(ext|x|ext.)\s*d{2,5})? #扩展
)''', re.VERBOSE)

7.14 re.IGNORECASE,re.DOTALL,re.VERBOSE

  • re.IGNORECASE: 忽略大小写
  • re.DOTALL: 让局点字符匹配所有字符,包括换行字符
  • re.VERBOSE: 忽略正则表达式字符串中的’空白符‘和’注释‘

posted @ 2020-10-23 11:24  辉哥运维  阅读(334)  评论(0)    收藏  举报