Python正则表达式

时间:2024-10-09 09:20:48

正则表达式
• 正则表达式是字符串处理的有力工具,比字符串自身提供的方法提供了更强大的处理功能。
• 例如判断一个字符串是否是合法的Email地址,可以通过构造一个规则(正则表达式),去判断字符串是否能够匹配。
在这里插入图片描述

元字符:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

re模块

Python通过re模块提供对正则表达式的支持。
使用re的一般步骤是先将正则表达式的字符串形式编译为Pattern实例
然后使用Pattern实例处理文本并获得匹配结果(一个Match实例)
最后使用Match实例获得信息,进行其他的操作。
函数
尝试从字符串的起始位置匹配一个模式,如果不是起
始位置匹配成功的话,match()就返回None。

re.match(pattern, string, flags=0)
  • 1

在这里插入图片描述

flags:

在这里插入图片描述
匹配成功方法返回一个匹配的对象
使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。
在这里插入图片描述
方法
扫描整个字符串并返回第一个成功的匹配

re.search(pattern, string, flags=0)
  • 1

在这里插入图片描述
与的区别
只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None
而匹配整个字符串,直到找到一个匹配。
compile 函数
compile 函数用于编译正则表达式,生成一个正则表达式
( Pattern )对象,供 match() 和 search() 这两个函数使用。

re.compile(pattern[, flags])
  • 1

findall
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次 findall 匹配所有。

findall(string[, pos[, endpos]])
  • 1

•string 待匹配的字符串。
•pos 可选参数,指定字符串的起始位置,默认为 0。
•endpos 可选参数,指定字符串的结束位置,默认为字符串的长度

在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回

re.finditer(pattern, string, flags=0)
  • 1


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

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

在这里插入图片描述

sub(pattern, repl, string, count=0, flags=0)
  • 1

替换函数,将正则表达式 pattern 匹配到的字符串替换为 repl 指定的字符串, 参数 count 用于指定最大替换次数
贪婪 vs 不贪婪
当重复一个正则表达式时,如用 a*,操作结果是尽可能多地匹配模式。 .* 的本质是“贪婪”的
在这种情况下,解决方案是使用不贪婪的限定符 *?、+?、?? 或{m,n}?,尽可能匹配小的文本。

正则表达式集锦

✓ 最简单的正则表达式是普通字符串,可以匹配自身
✓ ‘[pjc]ython’可以匹配’python’、‘jython’、‘cython’
✓ '[a-zA-Z0-9]'可以匹配一个任意大小写字母或数字
✓ '[^abc]‘可以一个匹配任意除’a’、‘b’、‘c’之外的字符
✓ ‘python|perl’或’p(ython|erl)‘都可以匹配’python’或’perl’
✓ 子模式后面加上问号表示可选。r’(http://)?(www.)?’只能匹配
‘’、‘’、‘’和’’
✓ ‘^http’只能匹配所有以’http’开头的字符串
✓ (pattern):允许模式重复0次或多次
✓ (pattern)+:允许模式重复1次或多次
✓ (pattern){m,n}:允许模式重复m~n次
✓ ‘(a|b)c’:匹配多个(包含0个)a或b,后面紧跟一个字母c。
✓ ‘ab{1,}’:等价于’ab+’,匹配以字母a开头后面带1个至多个字母b的字符串。
✓ ‘1{1}([a-zA-Z0-9._]){4,19}KaTeX parse error: Undefined control sequence: \w at position 53: …、“.”的字符串。 ✓ '^(\̲w̲){6,20}’:匹配长度为6-20的字符串,可以包含字母、数字、下划线。
✓ ‘^\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}KaTeX parse error: Undefined control sequence: \d at position 33: …址。 ✓ '^(13[4-9]\̲d̲{8})|(15[01289]…’:检查给定字符串是否为移动手机号码。
✓ ‘2+KaTeX parse error: Undefined control sequence: \w at position 28: …包含英文字母大小写。 ✓ '^\̲w̲+@(\w+\.)+\w+’:检查给定字符串是否为合法电子邮件地址。
✓ r’(\w)(?!.
\1)’:查找字符串中每个字符的最后一次出现。
✓ r’(\w)(?=.
\1)’:查找字符串中所有重复出现的字符。
✓ ‘^(-)?\d+(.\d{1,2})?KaTeX parse error: Can't use function '\u' in math mode at position 33: …位小数的正数或负数。 ✓ '[\̲u̲4e00-\u9fa5]':匹…’:检查给定字符串是否为合法身份证格式。
✓ ‘\d{4}-\d{1,2}-\d{1,2}’:匹配指定格式的日期,例如2016-1-31。
✓ ‘^(?=.[a-z])(?=.[A-Z])(?=.\d)(?=.[,._]).{8,}KaTeX parse error: Can't use function '\'' in math mode at position 86: …至少8位。 ✓ "(?!.*[\̲'̲\"\/;=%?]).+":如…
可以检查字符串是否为IP地址,字符串’888.888.888.888’这样的也能通过检查,但实际上并不是有效的IP地址。
• 同样的道理,正则表达式’^\d{18}|\d{15}$'也只负责检查字符串是否为18位或15位数字,并不保证一定是合法的身份证号。
re模块案例

>>> import re #导入re模块
>>> text = 'alpha. beta....gamma delta' #测试用的字符串
>>> re.split('[\. ]+', text) #使用指定字符作为分隔符进行分隔
['alpha', 'beta', 'gamma', 'delta']
>>> re.split('[\. ]+', text, maxsplit=2) #最多分隔2次
['alpha', 'beta', 'gamma delta']
>>> re.split('[\. ]+', text, maxsplit=1) #最多分隔1次
['alpha', 'beta....gamma delta']
>>> pat = '[a-zA-Z]+'
>>> re.findall(pat, text) #查找所有单词
['alpha', 'beta', 'gamma', 'delta']
>>> pat = '{name}'
>>> text = 'Dear {name}...'
>>> re.sub(pat, '', text) #字符串替换
'Dear ...'
>>> s = 'a s d'
>>> re.sub('a|s|d', 'good', s) #字符串替换
'good good good'
>>> s = "It's a very good good idea"
>>> re.sub(r'(\b\w+) \1', r'\1', s) #处理连续的重复单词
"It's a very good idea"
>>> re.sub(r'((\w+) )\1', r'\2', s)
"It's a very goodidea"
>>> re.sub('a', lambda x:x.group(0).upper(), 'aaa abc abde')
#repl为可调用对象
'AAA Abc Abde
>>> re.sub('[a-z]', lambda x:x.group(0).upper(), 'aaa abc abde')
'AAA ABC ABDE'
>>> re.sub('[a-zA-z]', lambda x:chr(ord(x.group(0))^32), 'aaa aBc abde')
#英文字母大小写互换
'AAA AbC ABDE'
>>> re.subn('a', 'dfg', 'aaa abc abde') #返回新字符串和替换次数
('dfgdfgdfg dfgbc dfgbde', 5)
>>> re.sub('a', 'dfg', 'aaa abc abde')
'dfgdfgdfg dfgbc dfgbde'
>>> re.escape('') #字符串转义
'http\\:\\/\\/www\\.python\\.org
>>> print(re.match('done|quit', 'done')) #匹配成功,返回match对象
<_sre.SRE_Match object at 0x00B121A8>
>>> print(re.match('done|quit', 'done!')) #匹配成功
<_sre.SRE_Match object at 0x00B121A8>
>>> print(re.match('done|quit', 'doe!')) #匹配不成功,返回空值None
None
>>> print(re.match('done|quit', 'd!one!')) #匹配不成功
None
>>> print(re.search('done|quit', 'd!one!done')) #匹配成功
<_sre.SRE_Match object at 0x0000000002D03D98>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

• 下面的代码使用不同的方法删除字符串中多余的空格,如果遇到连续多个空格则只保留一个,同时删除字符串两侧的所有空白字符。

>>> import re
>>> s = 'aaa bb c d e fff '
>>> ' '.join(s.split()) #直接使用字符串对象的方法
'aaa bb c d e fff'
>>> ' '.join(re.split('[\s]+', s.strip())) #同时使用re中的函数和字符串对象的方法
'aaa bb c d e fff'
>>> ' '.join(re.split('\s+', s.strip())) #与上一行代码等价
'aaa bb c d e fff'
>>> re.sub('\s+', ' ', s.strip()) #直接使用re模块的字符串替换方法
'aaa bb c d e fff'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

• 下面的代码使用几种不同的方法来删除字符串中指定内容:

>>> email = "tony@tiremove_thisger.net"
>>> m = re.search("remove_this", email) #使用search()方法返回的match对象
>>> email[:m.start()] + email[m.end():] #字符串切片
'tony@'
>>> re.sub('remove_this', '', email) #直接使用re模块的sub()方法
'tony@'
>>> email.replace('remove_this', '') #直接使用字符串替换方法
'tony@'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

• 下面的代码使用以“\”开头的元字符来实现字符串的特定搜索。

>>> import re
>>> example = 'Beautiful is better than ugly.'
>>> re.findall('\\bb.+?\\b', example) #以字母b开头的完整单词
#此处问号?表示非贪心模式
['better']
>>> re.findall('\\bb.+\\b', example) #贪心模式的匹配结果
['better than ugly']
>>> re.findall('\\bb\w*\\b', example)
['better']
>>> re.findall('\\Bh.+?\\b', example) #不以h开头且含有h字母的单词剩余部分
['han']
>>> re.findall('\\b\w.+?\\b', example) #所有单词
['Beautiful', 'is', 'better', 'than', 'ugly']
>>> re.findall('\w+', example) #所有单词
['Beautiful', 'is', 'better', 'than', 'ugly']
>>> re.findall(r'\b\w.+?\b', example) #使用原始字符串
['Beautiful', 'is', 'better', 'than', 'ugly']
>>> re.split('\s', example) #使用任何空白字符分隔字符串
['Beautiful', 'is', 'better', 'than', 'ugly.']
>>> re.findall('\d+\.\d+\.\d+', 'Python 2.7.13') #查找并返回形式的数字
['2.7.13']
>>> re.findall('\d+\.\d+\.\d+', 'Python 2.7.13,Python 3.6.0')
['2.7.13', '3.6.0']
>>> s = '<html><head>This is head.</head><body>This is body.</body></html>'
>>> pattern = r'<html><head>(.+)</head><body>(.+)</body></html>'
>>> result = re.search(pattern, s)
>>> result.group(1) #第一个子模式
'This is head.'
>>> result.group(2) #第二个子模式
'This is body.'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

◼ 正则表达式对象的match方法和search方法匹配成功后返回match对象。
match对象的主要方法有:
✓ group():返回匹配的一个或多个子模式内容
✓ groups():返回一个包含匹配的所有子模式内容的元组
✓ groupdict():返回包含匹配的所有命名子模式内容的字典
✓ start():返回指定子模式内容的起始位置
✓ end():返回指定子模式内容的结束位置的前一个位置
✓ span():返回一个包含指定子模式内容起始位置和结束位置前一个位置的元组。

>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")
>>> m.group(0) #返回整个模式内容
'Isaac Newton'
>>> m.group(1) #返回第1个子模式内容
'Isaac'
>>> m.group(2) #返回第2个子模式内容.
'Newton'
>>> m.group(1, 2) #返回指定的多个子模式内容
('Isaac', 'Newton')
>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
>>> m.group('first_name') #使用命名的子模式
'Malcolm'
>>> m.group('last_name')
'Reynolds'
>>> m = re.match(r"(\d+)\.(\d+)", "24.1632")
>>> m.groups() #返回所有匹配的子模式(不包括第0个)
('24', '1632')
>>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "Malcolm Reynolds")
>>> m.groupdict() #以字典形式返回匹配的结果
{'first_name': 'Malcolm', 'last_name': 'Reynolds'}
>>> s = 'aabc abcd abbcd abccd abcdd'
>>> re.findall(r'(\b\w*(?P<f>\w+)(?P=f)\w*\b)', s)
[('aabc', 'a'), ('abbcd', 'b'), ('abccd', 'c'), ('abcdd', 'd')]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

  1. a-zA-Z ↩︎

  2. a-zA-Z ↩︎