1. 什么是正则表达式

正则表达式(regular expressions),也称为 “regex” 或 “regexp” 是使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,这样程序就可以将该模式与任意文本字符串相匹配。

使用正则表达式,可以为要匹配的可能字符串集指定规则;此集可能包含英语句子,电子邮件地址,tex命令或你喜欢的任何内容

正则表达式引擎

采用不同算法,检查处理正则表达式的软件模块 pcre (perl compatible regular expressions)

正则表达式的元字符分类: 字符匹配,匹配次数,位置锚定,分组

python的正则表达式是pcre标准的。

2. 正则表达式基础

# 字符匹配

. 匹配任意单个字符(换行符除外)

[]匹配指定范围内的任意单个字符: [0-9] [a-z]

^[xxx]以[]内的任意字符开头

[^xxx]: 除了[]内的字符,相当于取反

# 匹配次数

用于指定前面的字符要出现几次

* 匹配前面的字符的任意次,包括0次, 贪婪匹配:尽可能长的匹配
.* 任意长度的任意字符
? 匹配其前面的字符0或1次
+ 匹配前面的字符至少1次
{n} 匹配前面的字符n次
{m,n} 匹配前面的字符至少m次,最多n次如{1,3} 匹配1到3次
{n,} 匹配前面的字符至少n次

# 位置锚定
# 用于定位出现的位置

^ 行首

$ 行尾

^$ 空行

# 分组
() 分组,用()将多个字符捆绑在一起,当作一个整体处理
后向引用: \1,\2

# | 或者
a|b a 或 b
(a|a)bc abc或abc

# \ 转义
\ 反斜杠后面可以跟各种字符,以指示各种特殊序列。它也用于转义所有元字符.因此您仍然可以在模式中匹配它们,如果你需要匹配 [ 或 \,你可以在它们前面加一个反斜杠来移除它们的特殊含义:\[ 或 \\。
在python中取消转义推荐使用r,如果要匹配’\n’,因为’\n’有特殊含义:回车。要匹配’\n’可以以写’\\n’,在python中可以使用r’\n’。

\d 匹配任何十进制数,等价于类 [0-9]
\w 匹配任何字母与数字字符包括下划线;这相当于类 [a-za-z0-9_]。
\s 匹配任何空白字符;这等价于类 [ \t\n\r\f\v]。

\d 匹配任何非数字字符;这等价于类 [^0-9]。
\w 匹配任何非字母与数字字符;这相当于类 [^a-za-z0-9_]。
\s 匹配任何非空白字符;这相当于类 [^ \t\n\r\f\v]。

3. python中使用正则表达式

在python中使用正则表达式常用的模块为:re。

3.1 re常用的方法

# re.findall('正则表达式','待匹配的文本')  根据正则匹配出所有符合条件的数据,返回列表
>>> re.findall('[0-9]', "hello world 123")
['1', '2', '3']
# 如果匹配不到findall返回一个空列表

# re.finditer('正则表达式','待匹配的文本') 根据正则匹配出所有符合条件的数据,返回一个对象
>>> re.finditer('[0-9]', "hello world 123")     
<callable_iterator object at 0x7f3409296d68>
# 取值:
>>> res = re.finditer('[0-9]', "hello world 123")
>>> for i in res:
...     print(i.group())
... 
1
2
3

# 如果匹配不到finditer返回空。

# findall 和finditer功能一样,但是finditer更节省内存。

# re.search('正则表达式','待匹配的文本')   根据正则匹配到一个符合条件的就结束
>>> res = re.search('l', "hello world 123")     
>>> res
<_sre.sre_match object; span=(2, 3), match='l'>
>>> res.group()
'l'
# 匹配到一个就返回,group()返回具体的元素,如果匹配不到search返回none,使用group取值就会报错:
attributeerror: 'nonetype' object has no attribute 'goup'
    
# re.match('正则表达式','待匹配的文本') 根据正则从头开始匹配(文本内容必须在开头匹配上)
>>> res = re.match('e', "hello world 123")   # e 不在开头,所以匹配不上,返回none
>>> print(res)
none

>>> res = re.match('h', "hello world 123")  # h 为开头能匹配上
>>> print(res)
<_sre.sre_match object; span=(0, 1), match='h'>
>>> print(res.group())
h

#如果没有匹配到,match会返回none 使用group取值的时候也会直接报错
attributeerror: 'nonetype' object has no attribute 'group'


# search和match匹配不到都会报错,可以处理一下:
if res:
    print(res.group())
else:
    print('没有匹配到')
    
# re.split 分割
>>> re.split('[0-9]', "hello 123 world")    # 按匹配到的分割,返回一个列表   
['hello ', '', '', ' world'] 

# re.sub('要匹配的', '要替换的', '文本')  替换
>>> re.sub('[0-9]','a', "hello 123 world")  # 默认替换全部
'hello aaa world'
>>> re.sub('[0-9]','a', "hello 123 world",1) # 替换一次
'hello a23 world'
>>> re.sub('[0-9]','a', "hello 123 world",2) # 替换两次
'hello aa3 world'
# re.subn() 和re.sub 功能一样,但是返回元组 并提示替换了几处
>>> re.subn('[0-9]','a', "hello 123 world")    
('hello aaa world', 3)
>>> re.subn('[0-9]','a', "hello 123 world", 1)
('hello a23 world', 1)

# 如果一个正则表达式在程序中经常用到,这样每次都写太麻烦,可以使用compile将正则表达式的样式编译为一个正则表达式对象 (正则对象)
# 例如 正则表达式'^\d{3,6}'经常使用
>>> obj = re.compile('^\d{3,6}')
>>> obj.findall("123 hello")
['123']
>>> res = obj.search("123 hello")
>>> res.group()
'123'
# obj还可以使用 finditer,match,split,subn,sub

# 分组
>>> res = re.search('[1-9]\d{16}([0-9x])','37152119841105155x')   
>>> res.group()
'37152119841105155x'
>>> res.group(1)  # 只打印分组1里的内容,1为第一个分组,这里面只有([0-9x])所以打印x
'x'
>>> res = re.search('[1-9](\d{16})([0-9x])','37152119841105155x')
>>> res.group() 
'37152119841105155x'
>>> res.group(1)   # (\d{16}) 为第1个分组
'7152119841105155'
>>> res.group(2)	# ([0-9x]) 为第2个分组
'x'
# 这种取分组里的值也为索引取值

# findall优先打印出分组里的内容
>>> re.findall('[1-9]\d{16}([0-9x])','37152119841105155x')
['x']

# 取消分组: ?:
>>> res = re.findall('[1-9]\d{16}(?:[0-9x])','37152119841105155x')  
>>> res   # (?:[0-9x])
['37152119841105155x']

# 上面的分组为无名分组,分组也可以有名字。
# 有名分组  ?p<分组名称>
>>> res = re.search('[1-9](?p<first>\d{16})(?p<second>[0-9x])','37152119841105155x')
>>> res.group()
'37152119841105155x'
>>> res.group('first')
'7152119841105155'
>>> res.group('second')
'x'
# 分组后也可以使用索引到值:
>>> res.group(2)       
'x'

3.2 re模块练习

爬链家二手房前十页

import re
import requests 

for i in range(1,11):

    url = 'https://bj.lianjia.com/ershoufang/pg{}srs%e6%97%a7%e5%ae%ab/'.format(i)

    r = requests.get(url)

    title = re.findall('data-is_focus="" data-sl="">(.*?)</a>',r.text)
    price = re.findall('<span>([0-9]{3})</span>',r.text)

    address = re.findall('data-log_index="\d" data-el="region">(.*?)</a>', r.text)
    houseicon = re.findall('<span class="houseicon"></span>(.*?)</div>', r.text)



    res = zip(title,price,address,houseicon)
    for i in res:
    # print("%s \t%s(万) \t%s\t%s" % (i[0], i[1], i[2], i[3])) 
        print("""
    小区名: %s,
    总价: %s万,
    地址: %s,
    房型: %s""" % (i[0], i[1], i[2], i[3]))
    
# 执行结果:
[root@hans_tencent_centos82 module]# python3 houses.py 

    小区名: 红星楼小区 南北通透一居室 满五唯一商品房,
    总价: 185万,
    地址: 红星楼 ,
    房型: 1室1厅 | 46.46平米 | 南 北 | 简装 | 顶层(共6层) | 1989年建 | 板楼

    小区名: 旧宫北里 2室2厅 南 北,
    总价: 469万,
    地址: 旧宫北里 ,
    房型: 2室2厅 | 96.55平米 | 南 北 | 精装 | 高楼层(共9层) | 2004年建 | 板楼

    小区名: 亦庄北岸 3室1厅 南 北,
    总价: 558万,
    地址: 亦庄北岸 ,
    房型: 3室1厅 | 109.58平米 | 南 北 | 精装 | 中楼层(共15层) | 2008年建 | 板塔结合

参考内容:

python官方文档

内容扩展:

python对正则表达式的支持

python提供了re模块来支持正则表达式相关操作,下面是re模块中的核心函数。

函数 说明
compile(pattern, flags=0) 编译正则表达式返回正则表达式对象
match(pattern, string, flags=0) 用正则表达式匹配字符串 成功返回匹配对象 否则返回none
search(pattern, string, flags=0) 搜索字符串中第一次出现正则表达式的模式 成功返回匹配对象 否则返回none
split(pattern, string, maxsplit=0, flags=0) 用正则表达式指定的模式分隔符拆分字符串 返回列表
sub(pattern, repl, string, count=0, flags=0) 用指定的字符串替换原字符串中与正则表达式匹配的模式 可以用count指定替换的次数
fullmatch(pattern, string, flags=0) match函数的完全匹配(从字符串开头到结尾)版本
findall(pattern, string, flags=0) 查找字符串所有与正则表达式匹配的模式 返回字符串的列表
finditer(pattern, string, flags=0) 查找字符串所有与正则表达式匹配的模式 返回一个迭代器
purge() 清除隐式编译的正则表达式的缓存
re.i / re.ignorecase 忽略大小写匹配标记
re.m / re.multiline 多行匹配标记

说明: 上面提到的re模块中的这些函数,实际开发中也可以用正则表达式对象的方法替代对这些函数的使用,如果一个正则表达式需要重复的使用,那么先通过compile函数编译正则表达式并创建出正则表达式对象无疑是更为明智的选择。

到此这篇关于python 正则表达式基础知识点及实例的文章就介绍到这了,更多相关python 正则表达式 浅析内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!