正则表达式
正则表达式是用于处理字符串的工具,使用预定义的特定模式去匹配一类具有共同特征的字符串,主要用于快速、准确地完成复杂字符串的查找、替换等操作。
常用元字符和语法
一、基本字符集
基本字符集 | ||
元字符与语法 | 说明 | 表达式实例 |
. | 匹配除换行符外的任意单个字符 | a.c匹配 abc, acc 等类型字符串 |
\ | 转义字符 | a\.c匹配 a.c; a\\c 匹配 a\c |
[] | 用来表示一组字符 | a[bcd]e(同 a[b-d]e) 匹配 ade, ace, ade |
[^] | 不在[]中的字符 | [^abc]匹配除 a,b,c 之外的字符 |
预定义字符集(可用在字符集[]中) | ||
\d | 匹配任意数字,等价于[0-9] | a\dc匹配 a1c,a2c |
\D | 匹配任意非数字 | a\Dc匹配 abc,asc |
\s | 匹配任意空白字符,等价于[\t\n\r\f] | a\sc匹配a c |
\S | 匹配任意非空字符集 | a\Sc 匹配 abc 等 |
\w | 匹配任意数字、字母、下划线 | a\wc 匹配 a1c,abc,a_c |
\W | 匹配非数字、字母、下划线 | a\Wc匹配a c |
数量词(可用在字符或()之后,即重复限定符) | ||
* | 匹配位于*之前的字符0次或多次 | abc*匹配 ab,abccc等 |
+ | 匹配位于+之前的字符1次或多次 | abc+匹配 abc,abccc等 |
? | 匹配位于?之前的字符0次或多次 当此字符紧紧随任何其他限定符(*,+,?,{m},{m,n})之后,匹配模式为“非贪婪” | abc?匹配 ab和abc |
{m} | 匹配前一个字符m次 | ab{2}c 匹配 abbc |
{m,n} | 匹配前一个字符m至n次。 省略m则匹配0至n次 省略n则匹配m至无限次 | ab{1,2}c 匹配 abc和abbc |
边界匹配 | ||
^ | 匹配行首 | ^abc 匹配以abc为开始的行 |
$ | 匹配行尾 | $abc 匹配以abc为结尾的行 |
\A | 匹配字符串开头 | \Aabc 匹配 abcd |
\Z | 匹配字符串结尾 | abc\Z 匹配 dabc |
\b | 单词边界 | er\b 匹配 never |
\B | 非单词边界 | er\B 匹配 verb |
逻辑、分组 | ||
| | 匹配位于|之前或者之后的字符 | a|b 匹配 a 或 b |
() | 将位于()内的内容作为一个整体 | (abc){2} 匹配 abcabc |
提示1:贪婪与非贪婪匹配
正则表达式通常用于在文本中查找匹配的字符串。Python中数量词默认是贪婪的,即总是尝试匹配尽可能多的字符;相反,非贪婪总是尝试匹配尽可能少的字符
例如:正则表达式 “ab*”,如果在字符串 ”abbbc“ 中查找,将找到 ”abbb“;而如果使用表达式 ”ab*?“ ,将找到 "a"。
>>> import re
>>> re.findall(r"ab*","abbbc") #['abbb'] 为贪婪匹配
>>> re.findall(r"ab*?","abbbc") #['a'] 为非贪婪匹配
提示2:元字符可以单独使用,但在处理复杂字符串时,也可以组合使用。
示例:
(1)‘[a-zA-Z0-9]’ 匹配任意一个带小写字母或数字
(2)‘^(\w){6,15}$’ 匹配长度为6-15的字符串,可以包含数字、字母和下划线
(3)‘^\w+@(\w+\.)+\w+$’ 检查给定字符串是否为合法电子邮件
(4)‘\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$’ 检查给定字符串是否为合法IP地址
re模块常用方法
在Python中,主要使用re模块来实现正则表达式的操作
方法 | 描述 |
re.complie(pattern[,flags]) | 用于编译正则表达式,生成一个正则表达式对象 |
re.match(pattern,string[,flags]) 或match(string[pos,[endpos]]) | 从字符串的起始位置开始匹配,若匹配,返回match()对象,否正返回none |
re.findall(pattern,string[,flags]) 或findall(string[pos,[endpos]]) | 在字符串中找到正则表达式所匹配的所有字串,并返回一个列表,如果没有找到匹配的,则返回空列表 |
re.sub(pattern,repl,string[,count=0]) 或sub(repl,string[,count]) | 用于替换字符串中的匹配项 |
re.subn(pattern,string[,maxsplite=0]) 或sub(repl,string[,count]) | 作用是和sub()相同,返回一个二元元组。第一个元素是替换结果,第二个元素是替换次数 |
re.split(pattern,string[,maxsplit=0]) 或split(string[,maxsplit]) | 按照能够匹配的字符串分割后返回列表 |
re.search(patter,string[,flags]) 或search(string[,pos[,endpos]]) | 扫描整个字符串并返回第一个成功的匹配 |
说明1:
pattern 为正则表达式;string 为字符串;flags 为匹配选项,可以是re.l(忽略大小写)、re.M(多行匹配模式)等;pos 和 endpos 为搜索范围。
说明2:
具体使用时,既可以直接使用re模块的方法进行字符串处理,也可以将模式编译为正则表达式对象,然后使用正则表达式对象的方法操作字符串
1.直接使用re模块方法
例1:match实例
>>> import re
>>> s='Python:Java:C'
>>> re.match(r'Python',s) #匹配成功
<re.Match object; span=(0, 6), match='Python'>
>>> s='Java:Python:C'
>>> re.match(r'Python',s) #匹配失败
>>> #返回空值None
例2:search实例
>>> import re
>>> s='Python:Java:C'
>>> re.search(r'Python',s) #匹配成功
>>> <re.Match object; span=(0, 6), match='Python'>
>>> s='Java:Python:C'
>>> re.search(r'Python',s) #同样匹配成功
>>> <re.Match object; span=(5, 11), match='Python'>
例3:findall实例
re.findall(r'[a-zA-Z]+','python.c..Java...PHP') #运行返回值为['Pyhton','c','Java','PHP']
例4:sub、subn实例
>>> import re
>>> s='Python:Java:C'
>>> re.sub(r'P.*n','Ruby',s) #'Ruby:Java:C'
>>> re.subn(r'P.*n','Ruby',s) #('Ruby:Java:C', 1)
例5:split实例
>>> re.split('\.+','python.c..Java...PHP') #['python', 'c', 'Java', 'PHP']
2.使用正则表达式对象
例1:
>>> p=re.compile('to')
>>> p.match('To be,\nor not to be') #匹配失败
>>> p.search('To be,\nor not to be') #匹配成功
<re.Match object; span=(14, 16), match='to'>
>>> p.findall('To be,\nor not to be') #['to']
例2:
>>> p=re.compile(r'\d+')
>>> p.findall('one1two2three3four4') #['1', '2', '3', '4']
>>> #如果含有连续的数字,则会放在一起
>>> p.findall('one1two2three3four45') #['1', '2', '3', '45']
练习
例1:基本字符集
>>> import re
>>> re.findall(r'a.c','abc') #['abc']
>>> re.findall(r'a.c','acc') #['acc']
>>> re.findall(r'a.c','a.c') #['a.c']
>>> re.findall(r'a\\c','a\c') #['a\\c']
>>> re.findall(r'a[bcd]e','abe') #['abe']
>>> re.findall(r'a[b-d]e','abe') #['abe']
>>> re.findall(r'a[^bcd]e','abe') #[]
>>> re.findall(r'a[^bcd]e','afe') #['afe']
例2:预定义字符集
>>> re.findall(r'a\dc','a2c') #['a2c']
>>> re.findall(r'a\Dc','abc') #['abc']
>>> re.findall(r'a\sc','a c') #['a c']
>>> re.findall(r'a\Sc','abc') #['abc']
>>> re.findall(r'a\wc','a_c') #['a_c']
>>> re.findall(r'a\Wc','a c') #['a c']
例3:数量词(重复限定词)
>>> re.findall(r'abc*','ab') #['ab']
>>> re.findall(r'abc+','abc') #['abc']
>>> re.findall(r'abc?','abc') #['abc']
>>> re.findall(r'ab{2}c','abbc') #['abbc']
>>> re.findall(r'ab{1,2}c','abbc') #['abbc']
例4:边界匹配
>>> re.findall(r'^abc','abcd') #['abc']
>>> re.findall(r'abc$','ccabc') #['abc']
>>> re.findall(r'\Aabc','abcd') #['abc']
>>> re.findall(r'abc\Z','abc') #['abc']
>>> re.findall(r'er\b','never') #['er']
>>> re.findall(r'er\B','verb') #['er']
例5:逻辑、分组
>>> re.findall(r'abc|def','abc') #['abc']
>>> re.findall(r'abc|def','def') #['def']
Tips:
(...)作为分组,每遇到一个(),分组编号加1,使用分组的好处时匹配的子串会保存到每一个子组里,便于以后使用。假设表达式为(\d{4})-(\d{2})-(\d{2}),则匹配 2024-06-23,然后用分组编号为1、2、3分别获取年、月、日三个值。
>>> m=re.search(r'(\d{4})-(\d{2})-(\d{2})','2024-06-23')
>>> m.group() #返回值为'2024-06-23' ,若改为m.groups(),则结果为:('2024','06','23')
>>> m.group(1) #'2024'
>>> m.group(2) #'06'
>>> m.group(3) #'23'
综合实例
例1:匹配身份证号码并获取身份证中的年、月、日等信息
>>> x=r'[1-9][0-9]{5}(\d{4})(\d{2})(\d{2})[0-9]{3}[0-9x]'
>>> s='342530199901203240'
>>> p=re.compile(x)
>>> m=p.match(s)
>>> m.groups() #('1999', '01', '20')
>>> m.group(1) #'1999'
>>> m.group(2) #'01'
>>> m.group(3) #'20'
例2:多关键字任一匹配查找
>>> import re
>>> rg=r'Python|Java|C'
>>> s='Hello Java,Python Developer'
>>> p=re.compile(rg)
>>> p.findall(s) #['Java', 'Python']
例3:提取字符串的手机号码,手机号的前缀为136,长度为11位
>>> import re
>>> s='13612345678,1361234567,123a2345678,136 12345678,13712345678,13687654321'
>>> rg=r'136\d{8}'
>>> p=re.compile(rg)
>>> p.findall(s) #['13612345678', '13687654321']
例4:利用分组命名,提取字符串中的内容
知识点:(?P<name>...)分组除原有编号外,再加一个别名。假设表达式为(?P<Year>\d{4})-(?P<Month>\d{2})-(?P<Day>\d{2}),则匹配用于匹配 2024-06-23,然后用命名分组名称Year、Month、Day 获取年、月、日三个值。
>>> import re
>>> s='Learn 1998-07-12,Practice 1999-09-09,Complete 2000-01-01'
>>> rg=r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
>>> p=re.compile(rg)
>>> m=p.search(s)
>>> m.group('year') #'1998'
>>> m.group('month') #'07'
>>> m.group('day') #'12'
好啦,关于正则表达式和re模块的相关知识就分享到这啦,若有错误,请大佬指正,不能误导别人!!!!
我是梦璃,一个准大一新生~~~