Python模式匹配与正则表达式
1. 用正则表达式查找文本模式
1.1 正则表达式匹配步骤
- 用import re导入正则表达式模块
- 用re.compile()函数创建一个Regex对象(记得使用原始字符串)
- 向Regex对象的search()方法传入想查找的字符串。它返回一个Match对象。
- 调用Match对象的group()方法,返回实际匹配文本的字符串。
import re phone_number = "my phone number is 400-880-9999" re_phone = re.compile(r'\d{3}-\d{3}-\d{4}') mo = re_phone.search(phone_number) print(mo.group())
1.2 用正则表达式匹配更多模式
1.2.1 利用括号分组
假定想要将区号从电话号码中分离。添加括号将在正则表达式中创建“分组”: (\d\d\d)-(\d\d\d-\d\d\d\d)。然后可以使用group()匹配对象方法,从一个分组中获取匹配的文本。
正则表达式字符串中的第一对括号是第1组。第二对括号是第2组。向group()匹配对象方法传入整数 1 或 2,就可以取得匹配文本的不同部分。向group()方法传 入0或不传入参数,将返回整个匹配的文本。
import re my_phone = 'my phone number is 400-880-9898' mach_regex = re.compile(r'(\d{3})-(\d{3})-(\d{4})') mo = mach_regex.search(my_phone) print(mo.group(1))
如果想要一次就获取所有的分组,请使用groups()方法,注意函数名的复数形式。
import re my_phone = 'my phone number is 400-880-9898' mach_regex = re.compile(r'(\d{3})-(\d{3})-(\d{4})') mo = mach_regex.search(my_phone) print(mo.groups()) areaCode, mainNumber,secNumber = mo.groups() print(areaCode) print(mainNumber) print(secNumber)
1.2.2 用管道匹配多个分组
希望匹配许多表达式中的一个时,就可以使用管道。如Tom和jerry同时出现在字符串中,第一次出现的匹配文本,将作为Match对象返回。如下代码
import re sublien = "Tom and jreey" sublien1 = "jerry is good Tom" mo = re.compile(r'Tom|jerry') mo1 = mo.search(sublien) print(mo1.group()) mo2 = mo.search(sublien1) print(mo2.group())
假设你希望匹配'Batman'、'Batmobile'、'Batcopter'和'Batbat'中任意一个。因为所有这 些字符串都以 Bat 开始,所以如果能够只指定一次前缀,就很方便。
import re sublien = "'Batman is good" match_test = re.compile(r'Bat(man|mobile|copter|bat)') mo = match_test.search(sublien) print(mo.group()) print(mo.group(1))
1.2.3 用问号实现可选匹配
?:匹配前面括号字符0次或1次
import re sublien = "Batman is good" sublien1 = "Batwoman is good" match_test = re.compile(r'Bat(wo)?man') mo = match_test.search(sublien) mo1 = match_test.search(sublien1) print(mo.group()) print(mo1.group())
1.2.4 用星号匹配0次或多次
import re sublien = "Batman is good" sublien1 = "Batwoman is good" sublien2 = "Batwowowowowowoman is good" match_test = re.compile(r'Bat(wo)*man') mo = match_test.search(sublien) mo1 = match_test.search(sublien1) mo2 = match_test.search(sublien2) print(mo.group()) print(mo1.group()) print(mo2.group())
1.2.5 用+号匹配1次或多次
import re sublien = "Batman is good" sublien1 = "Batwoman is good" sublien2 = "Batwowowowowowoman is good" match_test = re.compile(r'Bat(wo)+man') mo1 = match_test.search(sublien1) mo2 = match_test.search(sublien2) print(mo1.group()) print(mo2.group())
1.2.6 使用{}匹配特定次数
1.2.7贪心和非贪心匹配
import re subline = "hahahahaha" #贪心匹配 subtest = re.compile(r'(ha){3,5}') mo = subtest.search(subline) print(mo.group()) #非贪心匹配 subtest1 = re.compile(r'(ha){3,5}?') mo1 = subtest1.search(subline) print(mo1.group())
1.2.8 findall()方法
作为 findall()方法的返回结果的总结,请记住下面两点:
1.如果调用在一个没有分组的正则表达式上,例如\d\d\d-\d\d\d-\d\d\d\d,方法 findall()将返回一个匹配字符串的列表,例如['415-555-9999', '212-555-0000']。
2.如果调用在一个有分组的正则表达式上,例如(\d\d\d)-(\d\d\d)-(\d\d\d\d),方 法 findall()将返回一个字符串的元组的列表(每个分组对应一个字符串),例如[('415', '555', '1122'), ('212', '555', '0000')]。
import re subline = "hahahahaha" #贪心匹配 subtest = re.compile(r'(ha)') mo = subtest.findall(subline) print(mo)
1.2.9正则表达式符号
- ?匹配零次或一次前面的分组。
- *匹配零次或多次前面的分组。
- +匹配一次或多次前面的分组。
- {n}匹配 n 次前面的分组。
- {n,}匹配 n 次或更多前面的分组。
- {,m}匹配零次到 m 次前面的分组。
- {n,m}匹配至少 n 次、至多 m 次前面的分组。
- {n,m}?或*?或+?对前面的分组进行非贪心匹配。
- ^spam 意味着字符串必须以 spam 开始。
- spam$意味着字符串必须以 spam 结束。
- .匹配所有字符,换行符除外。
- \d、\w 和\s 分别匹配数字、单词和空格。
- \D、\W 和\S 分别匹配出数字、单词和空格外的所有字符。
- [abc]匹配方括号内的任意字符(诸如 a、b 或 c)。
- [^abc]匹配不在方括号内的任意字符。
1.2.10不区分大小写的匹配
re.IGNORECASE参数
import re subline = "my name is root,the ROOT is haha" subline_test = re.compile(r'(root)',re.IGNORECASE) mo = subline_test.findall(subline) print(mo)
1.1.11用sub()方法替换字符串
Regex 对象的 sub()方法需要传入两个参数。第一个参数是一个字符串,用于取代发现的匹配。第二个参数是一个字符串,即正则表达式
import re subline = "my name is root,the ROOT is haha" subline_test = re.compile(r'(root)',re.I) mo = subline_test.sub('master',subline) print(mo)
通过传入 re.DOTALL 作为 re.compile()的第 二个参数,可以让句点字符匹配所有字符,包括换行字符。
re.VERBOSE表示增加注释
re.IGNORECASE表示忽略大小写