【python进阶 笔记】正则表达式

【python高级基础 笔记】正则表达式

目录

1. re模块

2. 匹配单个字符

3. 匹配多个字符

4.匹配开头结尾

4.1. 实例 判断变量名是否符合要求

4.2 实例 匹配邮箱地址

5. 匹配分组

5.1. | 实例:匹配出0-100之间的数字。

5.2. ( )实例:

5.3. \实例

5.4. (?P) (?P=name)实例

6. re高级用法(search、findall、sub、split...)

6.1. search 

6.2. findall 

6.3. sub 

6.4 split 


在Python中需要通过正则表达式对字符串进行匹配的时候,可以使用一个模块,名字为re。

1. re模块

re模块的使用

 #coding=utf-8

    # 导入re模块
    import re

    # 使用match方法进行匹配操作
    result = re.match(正则表达式,要匹配的字符串)

    # 如果上一步匹配到数据的话,可以使用group方法来提取数据
    result.group()

re模块示例(匹配以hello开头的语句):

 #coding=utf-8

    import re

    result = re.match(r"hello","hello python")  # 'r'是防止字符转义的(转义字符无效)

    result.group()

运行结果:hello

re.match函数:

re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。

函数语法

re.match(pattern, string, flags=0)
pattern 匹配的正则表达式
string 要匹配的字符串。
flags

标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

标志位可参考:https://www.runoob.com/python3/python3-reg-expressions.html#flags

2. 匹配单个字符

正则表达式的单字符匹配:

字符 功能
. 匹配任意1个字符(除了\n)
[ ] 匹配[ ]中列举的字符
\d 匹配数字,即0-9
\D 匹配非数字,即不是数字
\s 匹配空白,即 空格,tab键
\S 匹配非空白
\w 匹配单词字符,即a-z、A-Z、0-9、_
\W 匹配非单词字符

注意到:大写字母的匹配字符 与 小写字母的匹配字符 功能刚好相反。

3. 匹配多个字符

匹配多个字符的相关格式

字符 功能
* 匹配前一个字符出现0次或者无限次,即可有可无
+ 匹配前一个字符出现1次或者无限次,即至少有1次
? 匹配前一个字符出现1次或者0次,即要么有1次,要么0次
{m} 匹配前一个字符出现m次
{m,n} 匹配前一个字符出现从m到n次

示例1:*

需求:匹配出,一个字符串第一个字母为大写字母,后面都是小写字母并且这些小写字母可有可无。

#coding=utf-8
import re

ret = re.match("[A-Z][a-z]*","M")
print(ret.group())

ret = re.match("[A-Z][a-z]*","MnnM")
print(ret.group())

ret = re.match("[A-Z][a-z]*","Aabcdef")
print(ret.group())

运行结果:

M
Mnn
Aabcdef

4.匹配开头结尾

字符 功能
^ 匹配字符串开头
$ 匹配字符串结尾

4.1. 实例 判断变量名是否符合要求

import re


def main():
    names = ["age", "_age", "1age", "age1", "a_age", "age_1_", "age!", "a#123", "__________"]
    for name in names:
        # ret = re.match(r"[a-zA-Z_][a-zA-Z0-9_]*", name)  # 有弊端,开头符合后,后面的没有强制要求判断,即不一定能判断到结尾

        # ^规定开头  $规定结尾  
        # python中的match默认是从头开始判断的所以,在match中可以不写^,但是match不会判断结尾,所以
        # 当需要以xxx结尾的时候 还需要写上$
        ret = re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", name)  # 满足匹配则有返回值
        if ret:
            print("变量名:%s 符合要求....通过正则匹配出来的数据是:%s" % (name, ret.group()))
        else:
            print("变量名:%s 不符合要求...." % name)


if __name__ == "__main__":
    main()

运行结果:

变量名:age 符合要求....通过正则匹配出来的数据是:age
变量名:_age 符合要求....通过正则匹配出来的数据是:_age
变量名:1age 不符合要求....
变量名:age1 符合要求....通过正则匹配出来的数据是:age1
变量名:a_age 符合要求....通过正则匹配出来的数据是:a_age
变量名:age_1_ 符合要求....通过正则匹配出来的数据是:age_1_
变量名:age! 不符合要求....
变量名:a#123 不符合要求....
变量名:__________ 符合要求....通过正则匹配出来的数据是:__________

4.2 实例 匹配邮箱地址

匹配163的邮箱地址,且@符号之前有4到20位 英文字母、数字或下划线,例如[email protected]

import re


def main():
    email = input("please input e-mail addres:")
    # 如果在正则表达式中需要用到了某些普通的字符,比如 . 比如? 等,仅仅需要在他们前面添加一个 反斜杠进行转义
    ret = re.match(r"[a-zA-Z_0-9]{4,20}@163\.com$", email)
    # ret = re.match(r"[\w]{4,20}@163.com$", email)  # \w会匹配中文?不行? 实测可用\w
    if ret:
        print("%s 符合要求." % email)
    else:
        print("%s 不符合要求." % email)

if __name__ == "__main__":
    main()

5. 匹配分组

字符 功能
| 匹配左右任意一个表达式
(ab) 将括号中字符作为一个分组 (匹配括号内的表达式,也表示一个组)
\num 引用分组num匹配到的字符串
(?P<name>) 分组起别名
(?P=name) 引用别名为name分组匹配到的字符串

5.1. | 实例:匹配出0-100之间的数字。

# coding=utf-8

# 目标:匹配出0-100之间的数字。

import re

ret = re.match("[1-9]?\d","8")  # 这样写匹配不到100(三位数),匹配不了结尾
print(ret.group())  # 8

ret = re.match("[1-9]?\d","78")
print(ret.group())  # 78

# 不正确的情况
ret = re.match("[1-9]?\d","08")
print(ret.group())  # 0 ,?匹配前一个字符出现1次或者0次,本处出现0次,符合匹配。为什么返回的是0而不是08?

# 修正之后的
ret = re.match("[1-9]?\d$","08")  # 还是匹配不到100(三位数)
if ret:
    print(ret.group())
else:
    print("不在0-100之间")

# 添加|
ret = re.match("[1-9]?\d$|100","8")
print(ret.group())  # 8

ret = re.match("[1-9]?\d$|100","78")
print(ret.group())  # 78

ret = re.match("[1-9]?\d$|100","08")
# print(ret.group())  # 不是0-100之间

ret = re.match("[1-9]?\d$|100","100")
print(ret.group())  # 100

5.2. ( )实例:

1). 匹配出163、126、qq邮箱

import re

ret = re.match("\w{4,20}@163\.com", "[email protected]")
# \w匹配单词字符,即a-z、A-Z、0-9、_ ,此处匹配@符号之前有4到20位 英文字母、数字或下划线
print(ret.group())  # [email protected]

ret = re.match("\w{4,20}@(163|126|qq)\.com", "[email protected]")  # |匹配左右任意一个表达式
print(ret.group())  # [email protected]

ret = re.match("\w{4,20}@(163|126|qq)\.com", "[email protected]")
print(ret.group())  # [email protected]

ret = re.match("\w{4,20}@(163|126|qq)\.com", "[email protected]")  # 不匹配时无返回
if ret:
    print(ret.group())
else:
    print("不是163、126、qq邮箱")  # 不是163、126、qq邮箱

执行结果:

[email protected]
[email protected]
[email protected]
不是163、126、qq邮箱

2). 提取区号和电话号码

import re
ret = re.match("([^-]*)-(\d+)","010-12345678")
# [^-]匹配除了-外的字符;*匹配前一个字符出现0次或者无限次;+匹配\d(数字)1次或者无限次
print(ret.group())  # 010-12345678
print(ret.group(1))  # 010
print(ret.group(2))  # 12345678

注:[^...] :匹配不在[]中的字符。

如:[^abc] 匹配除了a,b,c之外的字符;[^-]匹配除了-外的字符。

5.3. \实例

\num实例:

需求:匹配出<html><h1>hello</h1></html

import re

labels = ["<html><h1>hello</h1></html>", "<html><h1>hello</h2></html>"]

for label in labels:
    ret = re.match(r"<(\w*)><(\w*)>.*</\2></\1>", label)
    if ret:
        print("%s 是符合要求的标签" % ret.group())
    else:
        print("%s 不符合要求" % label)

注:正则表达式内,第一个()是分组1,用\1匹配;第2个()是分组2,用\2匹配。

输出:

<html><h1>hello</h1></html> 是符合要求的标签
<html><h1>hello</h2></html> 不符合要求


注:\num引用分组num匹配到的字符串正则表达式内,第一个()是分组1,用\1匹配;第2个()是分组2,用\2匹配。

5.4. (?P<name>) (?P=name)实例

(?P<name>)分组起别名、(?P=name)引用别名为name分组匹配到的字符串。

需求:匹配出<html><h1>hello</h1></html>

#coding=utf-8

import re

ret = re.match(r"<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>hello</h1></html>")
print(ret.group())  # <html><h1>hello</h1></html>

ret = re.match(r"<(?P<name1>\w*)><(?P<name2>\w*)>.*</(?P=name2)></(?P=name1)>", "<html><h1>hello</h2></html>")
# print(ret.group())  # 不匹配,异常

解释:(?P<name1>\w*) 给分组起别名name1,分组匹配\w 0次或者无限次;(?P=name1)引用别名为name1分组匹配到的字符串。

6. re高级用法(search、findall、sub、split...)

6.1. search 

re.search 扫描整个字符串并返回第一个成功的匹配re.search(pattern, string, flags=0) 

匹配成功re.search方法返回一个匹配的对象,否则返回None。

我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。

re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

实例:匹配出文章阅读的次数。

# coding=utf-8
import re

ret = re.search(r"\d+", "阅读次数为 9999")
print(ret.group())  # 9999

6.2. findall 

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

(注: match 和 search 是匹配一次 findall 匹配所有。)

re.findall(string[, pos[, endpos]])
  • string 待匹配的字符串。
  • pos 可选参数,指定字符串的起始位置,默认为 0。
  • endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。

实例:统计出python、c、c++相应文章阅读的次数

#coding=utf-8
import re

ret = re.findall(r"\d+", "python = 9999, c = 7890, c++ = 12345")
print(ret)  # ['9999', '7890', '12345']

注:返回值是列表,不需要group。

6.3. sub 

Python 的re模块提供了re.sub用于替换字符串中的匹配项。

re.sub(pattern, repl, string, count=0, flags=0)
  • pattern : 正则中的模式字符串。
  • repl : 替换的字符串,也可为一个函数。
  • string : 要被查找替换的原始字符串。
  • count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
  • flags : 编译时用的匹配模式,数字形式。

前三个为必选参数,后两个为可选参数。

简单说:拿pattern和string匹配,匹配的结果换成repel,再把替换后的整个字符串返回。

实例:将匹配到的阅读次数加1。

# coding=utf-8
import re

ret = re.sub(r"\d+", '998', "python = 997")
print(ret)  # python = 998

repl 换成函数:

# coding=utf-8
import re


def add(temp):
    strNum = temp.group()  # 取出匹配到的值
    num = int(strNum) + 1
    return str(num)


ret = re.sub(r"\d+", add, "python = 997")  # 匹配到了,则调add函数(匹配出来的对象传给函数),函数返回值用来替换
print(ret)  # python = 998

ret = re.sub(r"\d+", add, "python = 99")
print(ret)  # python = 100

实例:从下面的字符串中取出文本

<div><p>技术要求:</p>
<p>1、一年以上 Python 开发经验,掌握面向对象分析和设计,了解设计模式</p>
<p>2、掌握HTTP协议,熟悉MVC、MVVM等概念以及相关WEB开发框架</p>
<p>3、掌握关系数据库开发设计,掌握 SQL,熟练使用 MySQL/PostgreSQL 中的一种<br></p>
<p>4、掌握NoSQL、MQ,熟练使用对应技术解决方案</p>
<p>5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js</p>
<p>&nbsp;<br></p></div>
# coding=utf-8
import re

string =r"<div><p>技术要求:</p><p>1、一年以上 Python 开发经验,掌握面向对象分析和设计,了解设计模式</p><p>2、掌握HTTP协议,熟悉MVC、MVVM等概念以及相关WEB开发框架</p><p>3、掌握关系数据库开发设计,掌握 SQL,熟练使用 MySQL/PostgreSQL 中的一种<br></p><p>4、掌握NoSQL、MQ,熟练使用对应技术解决方案</p><p>5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js</p><p>&nbsp;<br></p></div>"

ret = re.sub(r"<[^>]*>|&nbsp;|\n", "", string)
# [^>]*匹配除了>之外的字符,<[^>]*>即匹配<...>。总体匹配<...>、空格、换行
print(ret) 

注:...

6.4 split 

根据匹配进行切割字符串,并返回一个列表。即按照能够匹配的子串将字符串分割后返回列表。

re.split(pattern, string[, maxsplit=0, flags=0])
  • pattern:匹配的正则表达式;
  • string:要匹配的字符串;
  • maxsplit:分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数;
  • flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

实例:按照:和 (空格)切割字符串“info:xiaoZhang 33 shandong”

# coding=utf-8
import re

ret = re.split(r":| ","info:xiaoZhang 33 shandong")
print(ret)  # ['info', 'xiaoZhang', '33', 'shandong']

更多可参考菜鸟教程:https://www.runoob.com/python3/python3-reg-expressions.html#flags

----------end-------------

发布了50 篇原创文章 · 获赞 10 · 访问量 6616

猜你喜欢

转载自blog.csdn.net/qq_23996069/article/details/104069963