一、正则表达式
1. 简介
正则表达式(regular expression)(regex)(RE),用来简洁表达一组字符的表达式,由字符和操作符构成。
正则表达式常用于文本处理,表达文本类型的特征,同时查找或替换一组字符串、匹配字符串的全部或部分
2. 正则表达式中的符号
按照符号的功能,可将其分为三类,一般情况下表达式都是由这三种符号组成的。
2.1 正则字符
正则符号 | 描述 | 实例 |
---|---|---|
\ |
转义字符。例如, ‘n’ 匹配字符 ‘n’。 | |
( ) |
标记一个子表达式的开始和结束位置。 | \( \) |
. | 匹配除换行符 \n 之外的任何单字符。 |
\. |
| | |左右表达式任意一个 | abc|def表示abc或def |
\d | 匹配字符串中的单个数字 | 等价于[0-9] |
\D | 匹配⾮数字,即不是数字 | |
a-zA-Z | 匹配全部英文字符 | |
0-9 | 匹配全部数字 | |
\w | 单词字符 | 等价于等价于[A-Za-z0-9] |
\W | 匹配非单词字符 | |
\s |
匹配字符串中的\n ,\t ,空格 |
|
\S |
匹配非空白字符 | |
[] |
中括号内任意正则符号均可参与匹配 | `[abc]表示a、b、c,[a-z]表示a到z的单个字符 |
[^] | 当在方括号表达式中使用,^对其后的正则表达式进行了反义表达。 | [^abc]表示非a或非b或非c的单个字符 |
2.2 限定字符
正则符号 | 描述 | 匹配自己时 |
---|---|---|
* | 匹配前面的子表达式零次或多次。 | abc*表示ab、abc、abcc、abccc等 |
? | 匹配前面的子表达式零次或一次 | abc*表示ab、abc |
+ | 匹配前面的子表达式一次或多次。 | abc+表示abc、abcc、abccc等 |
{m} | n 是一个非负整数。匹配确定的 m 次。 | ab{2}c表示abbc |
{m,} | m 是一个非负整数。至少匹配m 次。 | |
{m, n} | m 和 n 均为非负整数,其中m <= n。扩展前一个字符m至n次(含n) | ab{1,2}c表示abc,abbc |
2.3 定位字符
正则符号 | 描述 | 匹配自己时 |
---|---|---|
^ | 匹配输入字符串的开始位置。 | \^ |
$ | 匹配输入字符串的结尾位置 | \$ |
\b | 匹配一个单词边界,即字与空格间的位置 | |
\B | 非单词边界匹配 |
2.4 经典实例
正则符号 | 描述 |
---|---|
^[A-Za-z]+$ | 由26个字母组成的字符串 |
^[A-Za-z0-9]+$ | 由26个字母和数字组成的字符串 |
^-?\d+$ | 整数形式的字符串 |
^ [1-9]*[0-9]*$ | 正整数形式的字符串 |
[1-9]\d{5} | 中国境内邮政编码,6位 |
[\u4e00-\u9fa5] | 匹配中文字符 |
\d{3}-\d{8}|\d{4}-\d{7} | 国内电话号码 3位-8位或4位-7位 |
二、re库
1. 简介
2. 常用方法
re库常用函数 | 作用 |
---|---|
re.compile(r'\w{3}') |
re模块下的compile() 函数将正则表达式的字符串形式编译为一个 Pattern 对象 特别提示:正则表达式使用时,对特殊字符进行转义,所以如果我们要使用原始字符串,需在字符串前面加一个r 前缀。 |
re.search(pattern,string) |
在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象 |
re.match(pattern, string) |
从一个字符串的开始位置起匹配正则表达式,返回match对象 |
re.findall(pattern, string) |
根据pattern返回匹配结果(列表) |
re.finditer(pattern, string) |
搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象 |
re.split(pattern, string) |
使用pattern分割string,返回列表 |
re.sub(pattern, repl, string) |
使用repl替换string中的pattern |
2.1 re.search(pattern,string,flags=0)
pattern:匹配的正则表达式
string:要匹配的字符串
flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
flags 如:
re.I 忽略大小写
re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
re.M 多行模式
re.S 即为 . 并且包括换行符在内的任意字符(. 不包括换行符)
re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
re.X 为了增加可读性,忽略空格和 # 后面的注释
2.2 re.match(pattern,string,flags=0)
(1)与re.search()的区别在于:
re.match()是从起始位置就匹配成功,否则返回none;
re.search()匹配整个字符串,直到找到一个匹配成功的。注意:一次匹配,如果后面还有匹配的也不会查找了.
(2)提取数据:group
- group()用来提取分组截获的字符串,()用来分组。
- group() 同group(0)用来表示匹配正则表达式整体结果。
- group(1) 列出第一个括号匹配部分,group(2) 列出第二个括号匹配部分,group(3) 列出第三个括号匹配部分。
- 当嵌套分组时(有两层括号),即
r'((expression1)(expression2))'
的情况时,最外层的分组被解释成一个整体group(1),里层的分组解释从group(2)开始 - 没有匹配成功的,re.search()返回None。
(3)常用方法
group(): 用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0)
span(): 返回匹配字符串的起始位置
start():用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;
end():用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0
2.2 re.findall(string[, pos[, endpos]])
- 其中,string 是待匹配的字符串,pos 和 endpos 是可选参数,指定字符串的起始和终点位置,默认值分别是 0 和 len (字符串长度)。
- findall 以列表形式返回 。
import re
pattern=r'([a-z]+) ([a-z]+)'
text='hello World python'
#Example 1 search
search_list = re.search(pattern, text)
if search_list:
print(search_list)
print(search_list.group())
print(search_list.group(1))
print(search_list.group(2))
#结果
<re.Match object; span=(7, 18), match='orld python'>
orld python
orld
python
#Example 2 match
#2.1
match_list = re.match(pattern, text)
if match_list:
print(match_list)
#结果为none 因为match是从头开始匹配
#2.2
#Example 2 match
pattern2=r'([a-z]+) (\w{5})'
text='hello World python'
match_list = re.match(pattern2, text)
if match_list:
print(match_list)
print(match_list.group(1))
print(match_list.group(2))
#结果
<re.Match object; span=(0, 11), match='hello World'>
hello
World
#Example 3 findall
findall_list = re.findall(pattern, text)
if findall_list:
print(findall_list)
#结果
['hello', 'orld']
2.3 re.split(string[, maxsplit])
其中,maxsplit 用于指定最大分割次数,不指定将全部分割。跟字符串的分隔类似,但是这个更加灵活。
import re
pattern3=r'[\s\d]+'
text='hello World python'
split_list=re.split(pattern3,text) ## 表示遇到空白字符\s或者数字\d,都会切割。+表示如果有多个空格也可以切割。
print(split_list)
#结果
['hello', 'World', 'python']
#以上也可以写成
split_list=re.split(r'[\s\d]+','hello World python')
2.4 re.sub(repl, string[, count]) ==>re.sub(pattern, repl, string)
repl 可以是字符串也可以是一个函数:
- 如果 repl 是字符串,则会使用 repl 去替换字符串每一个匹配的子串,并返回替换后的字符串,另外,repl 还可以使用 id 的形式来引用分组,但不能使用编号 0;
- 如果 repl 是函数,这个方法应当只接受一个参数(Match 对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
- count用来指定最多替换的次数,默认为全部替换。
#Example 1 将数字进行更改
pattern = '\d+'
repl = 'NUM'
string = """Python是一门面向对象的编程语言,诞生于1991年。\
一般情况下Python是Java的20%,所以说人生苦短,我用Python。"""
re.sub(pattern, repl, string)
#Example 2 对某一个词汇进行同一表达
text = 'Python是一门面向对象的编程语言,诞生于1991年。\
一般情况下Python语言是Java的20%。Python目前使用人数很多。'
pattern = '[(Python语言)+(Python)]+' #要加+,否则变成[]内任一字符参与替换,从而导致多次替换
repl = 'Python语言'
re.sub(pattern, repl, text)
#Example 3 替换函数用法
def read_num(num):
num_temp = num.group()
num = int(num_temp) + 1
return str(num)
s = "阅读次数为:999,浏览次数为2000"
ret = re.sub(r"\d+",read_num,s)
print(ret)
#print结果:阅读次数为:1000,浏览次数为2001
#sub方法会将匹配到的数据依次传到方法read_num中,\
#所以我们首先要使用group方法获取到每个参数的具体内容,然后将这个字符串转为int类型,再加1,注意return的时候要转为字符串,这个位置的值只能是字符串
3. 贪婪与非贪婪
- 贪婪匹配:Python默认贪婪匹配,即尽可能多的匹配。
- 非贪婪匹配:在 “*” “?” “+” “{m,n}”的后面加上?就可以做到非贪婪,尽可能少的匹配
s=“this is a number: 0312-265-8888”
ret = re.match(r".+(\d+-\d+-\d+)",s) #因为要匹配数字,所以把号码用括号括起来
ret.group()
#'this is a number:0512-587-4567' #这个结果是这种方式提取到的号码,明显不是我们想要的.
#贪婪方式:前面的.+尽可能的匹配多一些,后面的\d+只要有一个数字就可以满足(造成group(1)前一个只有一个2),所以别的数字都归到了.+里面
ret.group(1)
#'2-587-4567'
#改成非贪婪模式
ret = re.match(r".+?(\d+-\d+-\d+)",s)
ret.group(1)
#'0312-265-8888' 此时尽可能多的匹配后面的\d+。