正则表达式的作用
我们先简单说一下,正则表达式是用来干什么的。
根据正则表达式表达的含义,我们可以用它来:
测试目标字符串是否符合规则
按照规则从目标字符串提取内容
从两个例子开始
我们使用两个简单的例子来说明正则标识表达式所起的上述两个作用。
如果你是首次接触正则表达式,你还可以先记下这两点:
- 正则表达式本身也使用字符串来表达。
- 用来标识正则表达式的字符串符合一定的语法规则(后面会讲具体的规则)。
可以看例子了。
例1
给定一个表示日期的字符串,请判断其是否符合形如2022-08-05这样的格式。
使用正则标识来编写代码:
import re
text1 = '2012-12-12'
text2 = '2012-12-123'
pattern = r'^\d{4}-\d{2}-\d{2}$'
match = re.search(pattern, text1, re.I) # 返回Match对象
if match is None:
print(f'{text1}为非法日期格式')
else:
print(f'{text1}为合法日期格式')
match = re.search(pattern, text2, re.I) # 返回Match对象
if match is None:
print(f'{text2}为非法日期格式')
else:
print(f'{text2}为合法日期格式')
2012-12-12为合法日期格式
2012-12-123为非法日期格式
例2
给定一个字符串,格式形如:
上市时间: 1998或上市时间: 2022年这样。
请从字符串中抽取年份的信息。
如果使用正则表达式来编码,代码非常简单(只是未学过正则表达式的表示看不懂)。
import re
text = '上市时间: 1998'
pattern = r'\d+'
match = re.search(pattern, text, re.I) # 返回Match对象
print(match.group())
1998
以上例子只是展示了正则表达式的很简单的用法。
要掌握正则表达式,说难不难,说易也不易。
看完本文并完成本文中的代码实践,一般的使用场景就能基本能应付了。
正则表达式的组成
正则表达式的组成成分,记住口诀:
定元限排选转分。
它们分别为:
定位符
定位符用来指定匹配的边界。定位符有
^和$,分别指定匹配的内容以什么开头,和以什么结尾。
元字符
元字符用来指定相关字符元素是什么类型的字符。
限定符
限定符用来指定相关字符出现的次数。
排除字符
排除字符用来指定相关字符不为某种字符。
选择字符
选择字符用来表示多选项匹配。
转义字符
转义字符用来表示与元字符冲突的原始字符。
分组
分组用来在正则表达式中划出一个子表达式作为一个小组,这个小组看成一个整体,方便对其应用限定符、排除字符和选择字符。
定位符
定位符用来指定匹配的边界。
定位符有^和$,分别指定匹配的内容以什么开头,和以什么结尾。
看实例!
指定匹配的内容以tm开头
^tm
指定匹配的内容以tm结尾:
tm$
指定匹配的内容包含tm(不要求以其为开头或结尾):
tm
元字符
元字符用来指定相关字符元素是什么类型的字符。
比如例1的正则表达式:
r'\d+'
\d就是一种元字符,它表示匹配数字。这里也顺便提一下后面的+是什么意思。它其实是一个限定符,限定:数字出现一次到多次。
常用元字符如下表所示:
| 符号 | 代表意思 | 使用场景 |
|---|---|---|
| . | 匹配除换行符之外的所有字符 | . 单个换行符之外所有字符 |
| \d | 匹配数字0-9 | \d 匹配单个数字,1、2、3 |
| \D | 匹配非数字 | \D 匹配单个非数字,a、-、' |
| \w | 匹配字母、数字、下划线 | \w 匹配单个字母、数字、下划线,a、1、_ |
| \W | 匹配非字母、数字、下划线 | \W 匹配单个非字母、数字、下划线,{、-、[ |
| \s | 匹配空白字符 | \s 匹配单个空格、回车(\n)、制表符(\t) |
| \S | 匹配非空白字符 | \S 匹配单个非空格、换行(\n)、制表符(\t) |
| \b | 匹配单词的开始或结束,单词的分界符通常是空格,标点符号或换行。 | 在“I like mr or am"字符串中,\bm与mr中的m相匹配,但与am中的m不匹配 |
对于元字符,我们还有必要做出解释。
前文提到的定位符,以及后面提到的限定符、排除字符、选择字符、转义字符、分组字符,在严格意义上讲都是元字符。但是在本文中,我有意识地将它们进行更细致地区分,因为这种区分更加有助于我们理解正则表达式。
限定符
限定符用来指定相关字符出现的次数。
比如我们在上一节已经提到的+这个限定符,就是指定字符出现一次到多次。
常用限定符如下表所示:
| 符号 | 代表意思 | 使用场景 |
|---|---|---|
| * | 匹配前面的字符0次及0次以上 | \d* 匹配数字,123、02、空 |
| + | 匹配前面的字符1次及1次以上 | \d+ 匹配数字,123、02、3 |
| ? | 匹配前面的字符0次或1次 | \d? 匹配数字,2、空 |
| {m,n} | 匹配前面的字符m次到n次 | \d{1,3} 匹配数字,2、12、123 |
| {n} | 匹配前面的字符n次 | \d{2} 匹配数字,12 |
| {n,} | 匹配前面的字符n次及n次以上 | \d{2,} 匹配数字,12、123、1234 |
排除字符
排除字符用来指定相关字符不为某种字符。
比如指定,相关字符不为数字。
[^\d]
import re
text = '5个交易日'
pattern = r'[^\d]'
match = re.search(pattern, text) # 返回Match对象
print(match.group())
输出:
个
^在这里就是排除字符。等等!^不是定位符嘛?在这里怎么成了排除字符?
不用纠结一个字符起两种作用是否恰当,你只要记住:被中括号包围的^为排除字符。
选择字符
选择字符用来表示可以匹配多个选项。
import re
text = '大鸭梨'
pattern = r'香蕉|苹果|大鸭梨'
match = re.search(pattern, text) # 返回Match对象
print(match.group())
text = '苹果很好吃'
match = re.search(pattern, text) # 返回Match对象
print(match.group())
输出:
大鸭梨
苹果
如果要匹配的模式字符串前后还有其他字符,多个选项的部分要用圆括号包围起来:
import re
text = '小明爱吃大鸭梨'
pattern = r'爱吃(香蕉|苹果|大鸭梨)'
match = re.search(pattern, text) # 返回Match对象
print(match.group())
输出:
爱吃大鸭梨
或者后面跟着限定符:
import re
text = '小明爱吃大鸭梨苹果苹果'
pattern = r'爱吃(香蕉|苹果|大鸭梨){3}'
match = re.search(pattern, text) # 返回Match对象
print(match.group())
输出:
爱吃大鸭梨苹果苹果
转义字符
转义字符用来表示与元字符冲突的原始字符。
转义字符指的就是\。
我们知道,.表示匹配除换行符以外的任意字符。那我想匹配.这字符本身(就是点这个字符),怎么办?
这就需要转义,就是改变含义。.本身有特殊含义,要恢复成原始字符,就转义成\.。这个\就是转义字符,它负责把它后面出现的字符恢复成起原始的含义。
import re
text = '股票代码: 股票价格:1.98元'
pattern = r'\d+\.\d{2}'
match = re.search(pattern, text) # 返回Match对象
print(match.group())
输出:
1.98
分组字符
分组用来在正则表达式中划出一个子表达式作为一个小组,这个小组看成一个整体,方便对其应用限定符、排除字符和选择字符。
分组是使用圆括号划定的。
下面的代码展示了分组的使用,并且取得了分组匹配结果。
import re
text = '股票代码:sz000689'
pattern = r'股票代码:(\w{8})'
match = re.search(pattern, text) # 返回Match对象
# print(match.group(0)) # group(0)是整体匹配结果,而非分组匹配结果
print(match.group(1))
输出:
sz000689
再看看更多分组的情况:
import re
text = '股票代码:sz000689,股票价格: 19.20元'
pattern = r'股票代码:(\w{8}),股票价格: (.*)元'
match = re.search(pattern, text) # 返回Match对象
print(match.groups())
输出:
('sz000689', '19.20')
扩展阅读
re.search和re.findall的区别
re.search找到一个匹配项即返回,re.findall会搜索所有匹配项re.search返回Match对象,re.findall返回列表(list)对象。