Python正则表达式re模块,一文看懂【收藏】
1.1 用正则表达式查找文本
-
\d
匹配任何一个0-9
的数字 -
\d{3}
匹配这个模式3次,3是个变量 -
\d{3,5}
匹配这个模式3次到5次,这个事贪心匹配模式,如果出现五次,那么他就匹配最长的哪一个. -
\d{3,5}?
非贪心匹配模式,只匹配最短的那个,问号在花括号后边则代表是非贪心匹配 -
()
利用括号分组,第一个括号为第一组,以此类推,用group(1)形式返回分组内容 -
?
问号位于分组()?
后边,则代表可选匹配,有则匹配,没有就掠过 - 利用管道符
|
匹配多个分组,是或的关系,有第一个匹配第一个,没有则依次往后匹配 -
+
加号匹配一次或多次,意味着加号之前的分组至少得出现一次 -
*
星号匹配零次或多次,意味着星号前边的分组可以不存在,也可以出现多次,均可匹配。
案例:
- 匹配这样一个电话号码:
400-9946-555
\d{3}-\d{4}-\d{3}
1.1.1 创建正则表达式对象
Python中所有表达式的函数都在 re 模块中。需导入模块!
-
import re 模块详解:
Regex = re.compile(r'\d{3}-\d{4}-\d{3}')
- 向
re.compile()
传入一个正则表达式,即代表我们创建了一个表达式对象,简称:Regex对象,格式如上所示。
mo = Regex.search('My number is 415-555-4242.')
- search()在文本中查找该正则表达式的所有匹配,如果没有找到将返回 None, 找到了将返回一个Match对象
mo.group()
返回Match对象中实际匹配的文本。 - 向
案例:
phoneNumberRegex = re.compile(r'\d{3}-\d{3}-\d{4}')
mo = phoneNumberRegex.search('My number is 415-555-4242.')
print(str(mo.group()))
1.1.2 用括号为正则表达式分组
假定你想将029-33660111这样的座机电话号码区号单独提取出来,那么可以用括号为正则表达式分组:
r'(\d{3})-(\d{7})'
然后使用 group()匹配对象方法,从一个分组中获取匹配的文本,第一个括号为第一组,逐次增加,不传入参数或传入为0,则返回整个匹配。
案例:
如果想一次返回所有分组,则可以使用,
groups()
方法, 返回的是一个元组。
import pyperclip, re
def RegexPhoneNumber(regex, num=0):
""" 将400电话提取拷贝到剪贴板的程序 """
# 接收剪贴板的文本
text = pyperclip.paste()
# 创建正则表达式对象
textRegex = re.compile(regex)
# 匹配该表达式中的文本
mo = textRegex.search(text)
if mo is not None:
if num == 0:
text = pyperclip.copy(mo.group())
print('这段文字里有匹配的电话:' + mo.group())
num1, num2 = mo.groups() # 元组的多重赋值
print('这段文字里有匹配的电话:' + num1)
print('这段文字里有匹配的电话:' + num2)
else:
# 您的正则表达式分组了,并且只提取指定组的内容
text = pyperclip.copy(mo.group(num))
print('这段文字里有匹配的电话:' + mo.group(num))
else:
print('这段文字里没有匹配的电话!')
RegexPhoneNumber(r'(\d{3})-(\d{4}-\d{3})') # 匹配 400-9946-555 这种格式的正则
# RegexPhoneNumber(r'(\d{3})-(\d{4}-\d{3})', num=2)
1.1.3 利用管道匹配多个分组
字符|称为“管道”。匹配多个表达式中的一个,语法格式为:r'zhang|zhen',是或的关系,匹配这个或者那个。
案例:
>>> import re
>>> heroRegex = re.compile(r'zhang|zhen')
>>> mo1 = heroRegex.search('my name is zhang xing fu or zhang zhen?')
>>> mo1.group()
'zhang'
- 如果前缀通用,那么可以将前缀移到括号外边,括号内用管道匹配,如果传入参数将匹配括号内第一次匹配的值
案例:
>>> batRegex = re.compile(r'Bat(man|mobile|copter|bat)')
>>> mo = batRegex.search('Batmobile lost a wheel')
>>> mo.group(1)
>>> mobile
>>> mo.group()
>>> Batmobile
1.1.4 利用问号实现可选匹配
有时我们会有这样的需求,例如想匹配的某个选项不是必须的,如果存在就匹配,不存在则略过,匹配其他的正则,此时可以使用
()?
这样的方式。
案例1:
>>> import re
>>> 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'
案例2:匹配一个电话号,有区号的则匹配没有区号则直接匹配电话,例如:029-33660111这样的格式。
>>> import re
>>> phoneNumber = re.compile(r'(\d{3}-)?\d{7}')
>>> mo1 = phoneNumber.search('我们公司的点化石:029-33660111')
>>> mo1.group()
'029-3366011'
>>> mo2 = phoneNumber.search('我们公司的点化石:33660111')
>>> mo2.group()
'3366011'
1.1.5 用星号匹配零次或多次
* 这个符号称为星号,匹配零次或多次,也就意味着星号前边的分组可以不存在,也可以出现多次,均可匹配。与之类似的是用 加号匹配一次或多次,意味着加号之前的分组至少得出现一次。
-
* 号匹配零次或多次
-
+ 号匹配一次或多次
-
案例:
>>> batRegex = re.compile(r'Bat(wo)*man') >>> mo3 = batRegex.search('my name is Batman') >>> mo3.group() 'Batman' >>> mo3 = batRegex.search('my name is Batwoman') >>> mo3.group() 'Batwoman' >>> mo3 = batRegex.search('my name is Batwowowowowowoman') >>> mo3.group() 'Batwowowowowowoman' # 加号匹配 >>> sumRegex = re.compile(r'Bat(wo)+man') >>> mo = sumRegex.search('my name is Batwoman') >>> mo.group() 'Batwoman' >>> mo = sumRegex.search('my name is Batwowowowowoman') >>> mo.group() 'Batwowowowowoman'
1.2 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 >>> phoneNumber = re.compile(r'\d{3}-\d{4}-\d{3}') >>> mo = phoneNumber.findall('公司的电话是:400-9946-555, 以前的是:400-6820-880') >>> mo ['400-9946-555', '400-6820-880'] >>> phoneNumber = re.compile(r'(\d{3})-(\d{4})-(\d{3})') >>> mo = phoneNumber.findall('公司的电话是:400-9946-555, 以前的是:400-6820-880') >>> mo [('400', '9946', '555'), ('400', '6820', '880')]
1.3 字符分类
-
常用字符分类的缩写代码:
缩写字符分类 表示 \d 0 到 9的任何数字 \D 除 0 到 9 的数字以外的任何字符 \w 任何字母、数字或下划线字符(可以认为是匹配“单词”字符) \W 除字母、数字和下划线以外的任何字符 \s 空格、制表符或换行符(可以认为是匹配“空白”字符) \S 除空格、制表符和换行符以外的任何字符
1.4 建立自己的字符分类
有时候你想匹配一组字符,但缩写的字符分类(\d、\w、\s 等)太宽泛。你可
以用方括号[]
定义自己的字符分类。
-
比较常用的几种方法总结
常用写法 表示的意思 [aeiouAEIOU] 匹配方括号内指定的字符 [a-zA-Z0-9] 用短横线表示字母或数字的范围 [.*?()] 方括号内普通的正则表达式符号不会被解释,他们匹配的就是本身自己 [^aeiouAEIOU] 方括号内开始位置加上^这个符号,将代表不匹配方括号内指定的所有字符,返回除过指定字符以外的字符 -
案例:
import re # 匹配方括号内指定的字符 >>> viowRegex = re.compile(r'[aeiouAEIOU]') >>> mo1 = viowRegex.findall('RoboCop eats baby food. BABY FOOD.') >>> mo1 ['o', 'o', 'o', 'e', 'a', 'a', 'o', 'o', 'A', 'O', 'O'] >>> viowRegex = re.compile(r'[^aeiouAEIOU]') >>> mo2 = viowRegex.findall('RoboCop eats baby food. BABY FOOD.') >>> mo2 ['R', 'b', 'C', 'p', ' ', 't', 's', ' ', 'b', 'b', 'y', ' ', 'f', 'd', '.', ' ', 'B', 'B', 'Y', ' ', 'F', 'D', '.']
1.5 插入字符和美元字符
可以在正则表达式的开始处使用插入符号(^),表明匹配必须发生在被查找文本开始处。类似地,可以再正则表达式的末尾加上美元符号(,表明整个字符串必须匹配该模式,也就是说,只匹配该字符串的某个子集是不够的。
-
比较常用的几种方法总结
常用写法 表示的意思 r'^Hello' 只匹配以'Hello'开始的字符串 r'\d$' 只匹配以数字结尾的字符串 r'^\w+\d+$' 只匹配以字母开头和数字结尾字符串 -
案例:
>>> Regex = re.compile(r'^Hello') >>> mo3 = Regex.search('Hello hai shi Hello') >>> mo3.group() 'Hello' >>> mo3 = Regex.search(' hai shi Hello') == None >>> mo3 True >>> Regex = re.compile(r'^\w+\d+$') >>> mo4 = Regex.search('zhangzhen456987') >>> mo4.group() 'zhangzhen456987'
1.6 通配字符
在正则表达式中,.(句点)字符称为“通配符”。它匹配除了换行之外的所有字符。
-
比较常用的几种方法总结
常用写法 表示的意思 r'.' 只匹配一个字符 r'.*' 匹配所有字符,贪心模式,尽可能多的匹配 r'.*? 非贪心匹配所有字符 re.compile(r'.*', re.DOTALL) 匹配所有字符,包括换行字符 re.compile(r'aoiue', re.I) 匹配字符,不论大小写都匹配
备注:如果想使用点-星匹配所有的字符包括换行,通过传入 re.DOTALL 作为 re.compile()的第二个参数,可以让句点字符匹配所有字符,包括换行字符。
1.7 正则表达式符号复习
- ?匹配零次或一次前面的分组。
- *匹配零次或多次前面的分组。
- +匹配一次或多次前面的分组。
- {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]匹配不在方括号内的任意字符。