Python中使用正则表达式

使用正则表达式处理字符串,能更加高效和简介。 首先,需要导入模块re

import re

常用的元字符:

  1. . 匹配除 “\n” 和 “\r” 之外的任何单个字符。
  2. ^ 匹配字符串开始位置。
  3. $ 匹配字符串中结束的位置。
  4. * 前面的原子重复 0 次、1 次、多次。
  5. ? 前面的原子重复 0 次或者 1 次。
  6. + 前面的原子重复 1 次或多次。
  7. {n} 前面的原子出现了 n 次。
  8. {n,} 前面的原子至少出现 n 次。
  9. {n,m} 前面的原子出现次数介于 n-m 之间。
  10. ( ) 分组,输出需要的部分。

常用的通用字符:

  1. \s 匹配空白字符。
  2. \w 匹配任意字母/数字/下划线。
  3. \W 和小写 w 相反,匹配任意字母/数字/下划线以外的字符。
  4. \d 匹配十进制数字。
  5. \D 匹配除了十进制数以外的值。
  6. [0-9] 匹配一个 0~9 之间的数字。
  7. [a-z] 匹配小写英文字母。
  8. [A-Z] 匹配大写英文字母。
search 第一个匹配串

找出子串第一个匹配位置。

se_str = 'i love you but just love you'
se_pat = 'love'
se_re = re.search(se_pat, se_str)
print(se_re)
print(se_re.span())

输出结果:

<re.Match object; span=(2, 6), match='love'>
(2, 6)
match

match与search匹配字符串不同:

  • match 在原字符串的开始位置匹配。
  • search 在字符串的任意位置匹配。
m_str = 'i love you'
re_com = re.compile('you')
print(re_com.match(m_str))
print(re_com.search(m_str).span())

输出结果:

None
(7, 10)

如果字符串为’you are my sunshine’,'you are my destiny’等,就能使用match匹配到’you’了。

finditer 匹配迭代器

返回所有子串匹配位置的迭代器。

fdr_str = 'i love you but just love you'
fdr_pat = 'love'
fdr_r = re.finditer(fdr_pat, fdr_str)
for i in fdr_r:
    print(i)

输出结果:

<re.Match object; span=(2, 6), match='love'>
<re.Match object; span=(20, 24), match='love'>
findall 所有匹配

findall 方法能查找出子串的所有匹配。

原字符串:

fda_str = '3号楼一单元1001,水费100.56'

目标是查找所有数字,所以需要使用正则表达式。

# r 去除转义字符
fda_pat = r'\d+'
fda_r = re.findall(fda_pat, fda_str)
for i in fda_r:
    print(i)

输出结果:

3
1001
100
56

水费 100.56 ,这里却分开显示,去掉了小数点,所以没有完成我们想要的效果。

匹配浮点数和整数

.? 表示匹配小数点(.)0 次或 1 次

因此,正则表达式可以修改成: \d+.?\d*

注意,后面使用 * 而不是 + ,是因为 + 表示至少有一位数字。加上前面的 \d+ ,表达式是需要匹配至少两位数。而 * 表示匹配前面字符 0 次、1 次或多次。

fda_str = '3号楼一单元1001,水费100.56'
fda_pat = r'\d+\.?\d*'
fda_r = re.findall(fda_pat, fda_str)
for i in fda_r:
    print(i)

输出结果:

3
1001
100.56

匹配正整数

写出匹配所有正整数的正则表达式。

^[1-9]\d*$

fda_lst = [11, 3, 1.3, 100.54, -5, 67]
fda_pat = r'^[1-9]\d*$'
re_lst = [i for i in fda_lst if re.match(fda_pat, str(i))]
print(re_lst)

输出结果:

[11, 3, 67]
re.I 忽略大小写

re.I 是方法的可选参数,表示忽略大小写。

re_str = 'This is the Way'
pat = r't'
r = re.finditer(pat, re_str, re.I)
for i in r:
    print(i.span())

输出结果:

(0, 1)
(8, 9)
split 分割单词

正则模块中 split 函数强大,能够处理复杂的字符串分割任务。

sp_str = 'This,;, is ; \t the || ,  Way  ;'
words_lst = re.split(r'[,\s;|]+', sp_str)
print(words_lst)

输出结果:

['This', 'is', 'the', 'Way', '']
sub 替换匹配串

替换匹配到的子串。

sub_str = 'This 2233 is station B 2233'
pat = re.compile(r'\d+')
mat = pat.sub("23333",sub_str)
print(mat)

输出结果:

This 23333 is station B 23333
compile 预编译

如果要用同一匹配模式,做很多次匹配,可以使用 compile 预先编译串。

案例:从一系列字符串中,挑选出所有正浮点数。

首先,生成预编译对象 rec:

rec = re.compile(r'^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$')

下面直接使用 rec,匹配列表中的每个元素,不用每次都预编译正则表达式,效率更高。

test_lst = [11, 'love', 3.33, -2.1, '666', 345, '2.33', 0.5]
res_lst = [i for i in test_lst if rec.match(str(i))]
print(res_lst)

输出结果:

[3.33, '2.33', 0.5]
贪心捕获

根据某个模式串,匹配到结果。

待爬取网页的部分内容如下所示,现在想要提取 <div> 标签中的内容。

content = '''<span>233333</span><div>bilibili</div><div>隐秘的角落</div>'''

通过正则提取 div 中的内容

result = re.findall(r'<div>.*</div>', content)
print(result)

输出结果:

['<div>bilibili</div><div>隐秘的角落</div>']

如果我们不想保留字符串最开始的 <div> 和结尾的 </div>,那么,就需要使用一对 () 去捕获。

result = re.findall(r'<div>(.*)</div>', content)
print(result)

输出结果:

['bilibili</div><div>隐秘的角落']
  • 结果中已经没有开始的 <div> ,结尾的 </div> 仅使用一对括号,便成功捕获到我们想要的部分。
  • (.*) 表示捕获任意多个字符,尽可能多地匹配字符,也被称为 贪心捕获
  • . 表示匹配除换行符外的任意字符。
非贪心捕获

上面的返回结果是: [‘bilibili</div><div>隐秘的角落’] ,对于剩下的 div 标签,我们也是不需要的,所以正则表达式还需要改进。

result = re.findall(r'<div>(.*?)</div>', content)

仅把上面的正则增加了一个 ? ,匹配串为: (.*?)

输出结果:

['bilibili', '隐秘的角落']

像这种匹配模式串,被称为非贪心捕获。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值