Python-7-Python正则表达式

7-1 初识正则表达式

通俗而言,就是通过某种规则,来匹配符合条件的字符序列。适用场景:快速查找、替换、匹配具有特殊格式的字符,如 文本替换、匹配电子邮箱、电话号码、IP地址等。匹配爬虫程序中某些特殊字符。

格式:

import re
re.findall(pattern, string, flags=0) #会将所有符合条件的字符放在一个列表中

其中:
pattern 是正则表达式的匹配规则
string 是要进行匹配的字符串
flags 是可选参数,进行特定条件的匹配。

例子:

#匹配字符串中所有的lemon.
import re
match_str = 'lemon&apple&lemoon&banana&lemooon&pear&lemoooon'
re.findall('lemon', match_str)
-----------------------
['lemon']

#选出 lemon lemoon lemooon lemoooon
import re
match_str = 'lemon&apple&lemoon&banana&lemooon&pear&lemoooon'
re.findall('lemo{1,4}n', match_str)
-----------------------
['lemon', 'lemoon', 'lemooon', 'lemoooon']

 

7-2 字符集

例子:

import re
match_str = 'bac | bbc | bcc | bdc | bec'
re.findall('b[ab]c', match_str) #匹配以b开头以c结尾,中间是a或b的字符串
-----------------------
['bac', 'bbc']

re.findall('b[^ab]c', match_str) # ['bcc', 'bdc', 'bec'] 匹配中间非ab的字符串
re.findall('b[a-d]c', match_str) # ['bac', 'bbc', 'bcc', 'bdc'] 匹配中间a-d的字符串
re.findall('b[^a-d]c', match_str) # ['bec'] 取反操作,不匹配中间是a-d的字符串

 

7-3 常见元字符

所有的元字符见:https://tool.oschina.net/uploads/apidocs/jquery/regexp.html

讲解3个常见的元字符:
(1) 数字字符,如”\d 匹配一个数字字符。等价于[0-9]"。"\D 匹配一个非数字字符。等价于[^0-9]"。
(2) 单词字符,如"\w 匹配包括下划线的任何单词字符。等价于“[A-Za-z0-9_]”","\W 匹配任何非单词字符。等价于“[^A-Za-z0-9_]"。
(3) 空白字符,如"\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]","\S 匹配任何非空白字符。等价于[^ \f\n\r\t\v]"。
(4) 点字符(.),匹配除"\n"之外的任何带个字符。

例子:

#数字字符
import re
match_str = 'l&a0b1c2d3e4f5%~'
re.findall('\d', match_str) #['0', '1', '2', '3', '4', '5']
re.findall('\D', match_str) #['l', '&', 'a', 'b', 'c', 'd', 'e', 'f', '%', '~']

#单词字符
import re
match_str = 'l&a0b1c2d3e4f5%~'
re.findall('\w', match_str) #['l', 'a', '0', 'b', '1', 'c', '2', 'd', '3', 'e', '4', 'f', '5']
re.findall('\W', match_str) #['&', '%', '~']

#空白字符 空格、制表符、换页等
import re
match_str = 'l&a0\nb1c2\rd3e4\tf 5%~'
re.findall('\s', match_str) #['\n', '\r', '\t', ' ']
re.findall('\S', match_str)
-----------------------
['l',
 '&',
 'a',
 '0',
 'b',
 '1',
 'c',
 '2',
 'd',
 '3',
 'e',
 '4',
 'f',
 '5',
 '%',
 '~']

#点字符(.)
import re
match_str = '\n123 abc\r'
re.findall('.', match_str) #['1', '2', '3', ' ', 'a', 'b', 'c', '\r']
re.findall('.', match_str, re.S) #['\n', '1', '2', '3', ' ', 'a', 'b', 'c', '\r'] re.S让'.'也可以匹配'\n'

 

7-4 数量词

取出完整的数字集合,如 123,34

1. 取出数字集合

#匹配字符,1-3次后输出
import re
match_str = '&a0b12c344d55&AC_'
re.findall('\d{1,3}', match_str) #['0', '12', '344', '55'] 1,,3中间不能有空格
re.findall('\d{1,}', match_str) # '0', '12', '344', '55'] 匹配1-n次

#匹配数字
import re
match_str = '&a0b12c344d55&AC6789_'
re.findall('\d{1,3}', match_str) # ['0', '12', '344', '55', '678', '9'] 
re.findall('\d{1,}', match_str) # ['0', '12', '344', '55', '6789'] 用{1,}匹配数字好一些

2. 取出单词集合

import re
match_str = '&lemon12banana34pear@56'
re.findall('[a-z]{4,6}', match_str) #['lemon', 'banana', 'pear'] 匹配a-z的任意字符4-6次

#匹配所有长度
match_str = '&lemon12banana34pear@56watermallon'
re.findall('[a-z]{4,}', match_str) # ['lemon', 'banana', 'pear', 'watermallon']

指定了匹配4-6次,为啥匹配了4次后还没停下来呢,因为贪婪匹配,匹配范围内最大的长度。


7-5 贪婪与非贪婪

贪婪:倾向于最大长度匹配
非贪婪:倾向于最小长度匹配

例子:

import re
match_str = '&lemon12banana34pear@56watermallon'
re.findall('[a-z]{4,6}?', match_str) #['lemo', 'bana', 'pear', 'wate', 'rmal'] '?'表示非贪婪,只匹配4-5中最小的长度
re.findall('[a-z]{4}?', match_str) #['lemo', 'bana', 'pear', 'wate', 'rmal'] 和上面等效

import re
match_str = 'lemooooon'
re.findall('lemo{1,}', match_str) # ['lemooooo'] 贪婪匹配,匹配出所有长度
re.findall('lemo{1,}?', match_str) #['lemo'] 非贪婪匹配,能匹配成功的情况下尽可能的少匹配。一个字符也没多

 

7-6 次数匹配

数量词:
* 代表匹配前面字符0次或多次 {0,}。
+ 代表匹配前面字符1次或多次 {1,}。
? 代表匹配前面字符0次或1次 {0,1}。

例子:

import re
match_str = 'lemo123, lemon345, lemonnnn567'
re.findall('lemon*', match_str) #['lemo', 'lemon', 'lemonnnn'] 匹配前面的'n'字符0次或多次
re.findall('lemon+', match_str) #['lemon', 'lemonnnn']
re.findall('lemon?', match_str) #['lemo', 'lemon', 'lemon']

 

7-7 定位符

定位符用于匹配字符串的边界,有两个常用定位符:
^ 匹配字符串开始位置
$ 匹配字符串结尾位置

例子:

import re
match_str = 'abcdef 123456 abcdef 456 abc' # match_str 是一个字符串
re.findall('^[a-z]{6}', match_str) #['abcdef'] #匹配小写字母开始,直到空格,匹配6位
re.findall('[a-z]{3}$', match_str) #['abc']

[^abc] 是取反的意思,表示不去匹配abc,^在中括号里面与外面是完全不一样的含义


7-8 组的匹配

一组字符的集合,使用的是小括号

例子:

import re
match_str = 'lemonlemonlemonappleappleapplepearpear'
#re.findall('(lemon){3}', match_str) #['lemon'] findall()会对多个组有一个去重的操作
re.search('(lemon){3}', match_str).group() #'lemonlemonlemon' 和这个不会去重

注:(lemon) 匹配 lemon 这一组字符,[lemon] 匹配中括号中的任意一个字符。

import re
match_str = 'lemonpear'
re.findall('[lemon]{3}', match_str) #['lem']
re.findall('(lemon)', match_str) #['lemon']

 

7-9 flags 可选参数

格式:

re.findall(pattern, string, flags=0)

例子:

import re
match_str = 'lemon LEMON'
re.findall('lemon', match_str) #['lemon'] 默认是区分大小写的
re.findall('lemon', match_str, re.I) #['lemon', 'LEMON'] re.I 让其不区分大小写

import re
match_str = 'lemon\n LEMON\n'
re.findall('lemon.', match_str, re.I|re.S) #['lemon\n', 'LEMON\n'] 让不区分大小写,且同时匹配\n

 

7-10 match 与 search函数

函数格式:

re.findall(pattern, string, flags=0) #搜索整个字符串,返回说有匹配组
re.match(pattern, string, flags=0) #从字符串首字符开始匹配,若首字符不匹配则返回None,若匹配则返回第一个匹配对象。
re.search(pattern, string, flags=0) #搜索整个字符串,若全都不匹配则返回None,若匹配则返回第一个匹配对象。

例子:

import re
match_str = '5678 lemon 1234'
re.findall('\d', match_str) #['5', '6', '7', '8', '1', '2', '3', '4']
re.match('\d', match_str).group() #'5' 若没匹配到使用group解引用报错
re.match('\d', match_str) #<re.Match object; span=(0, 1), match='5'>
re.search('\d', match_str).group() #'5'
re.search('\d', match_str) #<re.Match object; span=(0, 1), match='5'>

 

7-11 group 组匹配

例子:

import re
match_str = 'life is mostly happly, but sometimes sad'
#需求1:将"is mostly happly, but sometimes"匹配出来
r = re.search('life(.*)sad', match_str) #'.'表示除了换行符之外任何单个字符都可以匹配,'*'代表匹配前面的字符0次或多次
r #<re.Match object; span=(0, 40), match='life is mostly happly, but sometimes sad'> 匹配的对象、范围、字符串
r.group() #'life is mostly happly, but sometimes sad' 不传参数等于传0
r.group(0) #'life is mostly happly, but sometimes sad'
r.group(1) # ' is mostly happly, but sometimes '
#需求2: 将"is mostly happly"和"sometimes"匹配出来
r = re.search('life(.*)but(.*)sad', match_str)
r #<re.Match object; span=(0, 40), match='life is mostly happly, but sometimes sad'>
r.group() #'life is mostly happly, but sometimes sad'
r.group(1) #' is mostly happly, ' 匹配第一个分组的字符串
r.group(2) #' sometimes ' 匹配第二个分组的字符串

 注:match_str必须得是在一行,否则查找不到!

 

7-12 正则替换

1. sub()

re.sub(pattern, rep1, string, count=0, flags=0)

pattern 正则表达式
rep1 要替换的内容,也可以传入函数
string 被替换的字符串
count 默认为0,代表全部替换。1代表替换1次,2代表替换2次,依次类推。

例子:

#需求1:将lemon都替换为a
import re
match_str = 'lemon apple lemon pear'
re.sub('lemon', 'a', match_str, count=0) #'a apple a pear'
re.sub('lemon', 'a', match_str, count=1) #'a apple lemon pear' 只替换一次

#需求2:数字小于7的都转换为0,大于等于7的都转换为10
import re
match_str = 'lemon apple 123456789 lemon pear'

def transform(value):
    pass

re.sub('\d', transform, match_str, count=0) #'lemon apple  lemon pear' 可以发现1-9给全部替换了

==========================

import re
match_str = 'lemon apple 123456789 lemon pear'

def transform(value):
    print(value)

re.sub('\d', transform, match_str, count=0)
-------------------------
<re.Match object; span=(12, 13), match='1'> #可以看到value是一个对象
<re.Match object; span=(13, 14), match='2'>
<re.Match object; span=(14, 15), match='3'>
<re.Match object; span=(15, 16), match='4'>
<re.Match object; span=(16, 17), match='5'>
<re.Match object; span=(17, 18), match='6'>
<re.Match object; span=(18, 19), match='7'>
<re.Match object; span=(19, 20), match='8'>
<re.Match object; span=(20, 21), match='9'>
'lemon apple  lemon pear'

==========================

#通过返回函数,可以实现更新复杂的逻辑判断
import re
match_str = 'lemon apple 123456789 lemon pear'

def transform(value):
    match_num = value.group()
    if int(match_num) < 7: #可以使用type(match_num)查看类型为str,不能直接和数字比较大小
        return '0'
    else:
        return '10'
    print(type(match_num))

re.sub('\d', transform, match_str, count=0) #'lemon apple 000000101010 lemon pear'

这里允许用户提供一个接口,是允许用户自己实现替换逻辑的

 

posted on 2023-08-01 15:22  Hello-World3  阅读(25)  评论(0编辑  收藏  举报

导航