Python正则表达式

# -*- coding:utf-8 -*-

# 正则表达式
import re

# 使用match方法进行操作,匹配从头到尾的数据
# re.match(正则表达式,需要处理的字符串)
a = re.match("hello", "hello world")  # 检查第二个参数中是否存在第一个参数中的需求,也就是说检查第二个参数是否存在hello这个数据
print(a)  # 当满足你的需求时,这里就会有返回值,如果没有返回值,就说明不满足需求

a = re.match(r"hello", "Hello world")  # 因为python区分大小写,所以再第二个参数没有匹配到hello
print(a)  # 返回none

# 使用[]匹配单个字符

# 为解决上面的问题,当你不知道大小写的时候,可以在表达式中,用[]括号将可能出现的大小写括起来
a = re.match(r"[Hh]ello", "Hello world")  # 这样编写的话,不管hello还是Hello,都可以匹配到
print(a)

# 还可以这样,匹配h和e可能是以大小写存在在字符串中
a = re.match(r"[Hh][Ee]llo", "HEllo world")
print(a)

# 使用group方法提取匹配到的数据
aa = a.group()  # 如果上面match方法有匹配到数据的话,可以使用group方法提取数据出来
print(aa)

# 也可以这样,直接提取数据
a = re.match(r"速度与激情1", "速度与激情1").group()
print(a)
# 但是如果没有匹配到数据,就会报错'NoneType' object has no attribute 'group',意思是返回值为空(None)

a = re.match(r"速度与激情1", "速度与激情1")
print(a)
# 像上面那个例子,如果用户又想看第2部第3部呢?你不会也要跟着他按2和3吧
# 这里就可以使用\d来代替一个数字,如果是10,11,12的话,两个\d就可以代替两个数字如(\d\d)
a = re.match(r"速度与激情\d", "速度与激情2")  # \d可以匹配一个数字,0-9中都可以
print(a)

# 其他的单个匹配方法
"""
\小写和\大写的方法,刚好是相反的,小写的可以匹配的字符,大写就是除了不匹配小写的字符,其他都可以
字符 .  匹配任意一个字符,除了\n
字符 \d 匹配数字,即0-9
字符 \D 匹配非数字,即不是数字
字符 \s 匹配空白,即空格或Tab
字符 \S 匹配非空白
字符 \w 匹配单词字符,即a-z、A-Z、0-9、_
字符 \W 匹配非单个字符
"""

# 也可以限制可以查看多少部,比如我只能看到第8部
a = re.match(r"速度与激情[12345678]", "速度与激情8")  # 使用[]括号,将可以查看的数字范围填到里面
# 或者a = re.match(r"速度与激情[1-8]","速度与激情8") #[1-8]等价于[12345678]
print(a)

# 当你只想看123789的时候,可以这样:
a = re.match(r"速度与激情[1-37-9]", "速度与激情7")  # [1-37-9]等价于[123789],注意,因为一个括号只是匹配一个数字的,所以中间那里不是1-37
print(a)

# 匹配数字或者英文
a = re.match(r"速度与激情[1-8a-d]", "速度与激情a").group()  # [1-8a-d]等价于[12345678abcd]
print(a)
# 还可以
a = re.match(r"速度与激情[1-8a-dA-D]", "速度与激情A").group()
print(a)

# 匹配多个字符

"""
字符 *  匹配前一个字符出现0位或者无限位,即可有可无
字符 +  匹配前一个字符出现1位或者无限位,即至少有1位
字符 ?  匹配前一个字符出现1位或者0位,即要么有1位,要么没有
字符 {m}  匹配前一个字符出现m位,如{12},只出现12位
字符 {m,n}  匹配前一个字符出现从m到n位,如果{1,12},只出现1次至12位,即至少1位,至多12次
"""
# 加{}大括号可以匹配多个数字,如下,{}大括号仅用于挨着的前一个字符,如下就是挨着\d
a = re.match(r"速度与激情\d{1,2}", "速度与激情12")  # \d{1,2}的意思是可以匹配1位数字或者2位数字,也可以写{1,3},匹配3位数字
print(a)

# 也可以像匹配手机号码那样,只匹配11位
a = re.match(r"\d{11}", "12345678901")
print(a)

# ? 字符前面的东西,可有1个可没有
a = re.match(r"021-?\d{11}", "021-12345678901")  # 这里的 - 这个东西,可有1个可没有
print(a)

a = re.match(r"\d{1,4}-?\d{11}", "0211-12345678901")
print(a)

# 创建一堆数据
# 多行数据可以实现换行结果
html_he = """adcadcasd
ahjsgahjsdgfas
ajsdfghjafhdb
asdcygiuqw
nwciubc
cadsuydc
asdcsc
fwq
fj
dfy
dfgdjfy
"""
# . 是任意一位字符, * 是前面一个字符可以有0位或者无限位,但是 . 到\n的时候会终止,所以不会读取换行的数据
a = re.match(r".*", html_he).group()
print(a)
# 为解决不能读取所有数据,可以使用下面这个方法
a = re.match(r".*", html_he, re.S).group()  # re.S这个方法可以让 . 读取到\n的数据
print(a)
# * 可以匹配任何字符,就算是空白,也可以匹配
a = re.match(r".*", "").group()
print(a)

# 小测试,匹配出变量名是否有效
names = ['name1', 'name2', 'name3_', '_name4', '2_name5', '_name!']

for name in names:
    ret = re.match(r"[a-zA-Z_]+[\w]", name)  # 如果不用+号,就成了匹配前2位字符
    # 或者 ret = re.match(r"[a-zA-Z_][\w]*" , name) #与上面是等价的
    if ret:  # 当ret有值得时候,就执行if
        print("变量名 %s 符合要求,正则表达式匹配出来的数据是:%s " % (name, ret.group()))
    else:  # 当ret没有值得时候,就执行else
        print("变量名 %s 非法。" % name)
# 看似上面的代码正常运行了,但是,_name!并不符合变量名规则,因为以上所用到的代码,都是只匹配开头,没有匹配结尾
# 为解决上面的问题,接下来学习匹配开头和结尾

# 匹配开头和结尾

"""
re.match()方法是自带匹配开头的,但是没有自动判断结尾
字符 ^ 匹配字符串开头
字符 $ 匹配字符串结尾
"""

names = ['name1', 'name2', 'name3_', '_name4', '2_name5', '_name!']

for name in names:
    ret = re.match(r"[a-zA-Z_][\w]*$",
                   name)  # 在后面加一个 $ 符号,就代表着前面的正则匹配结束的时候,列表中的字符串也要同时匹配完,如果不加$这个符号,就会像上一个例子那样,只匹配前,没有匹配后
    if ret:  # 当ret有值得时候,就执行if
        print("变量名 %s 符合要求。" % name)
    else:  # 当ret没有值得时候,就执行else,没有返回值的时候,会显示None
        print("变量名 %s 非法。" % name)

# 练习:匹配出163的邮箱地址,且@符号之前有4到20位字母或数字或下划线
a = input("请输入您的邮箱地址:")
# 如果 . 符号没有加括号的话,那就成了匹配任意字符了,那么这里就要使用转义符 \ 来转义他为普通字符
# 如果在正则表达找那个,需要用到了某些普通的字符,比如 . ? * 等等,那么久要使用转义符了
ret = re.match(r"[a-zA-Z0-9_]{4,20}@163\.com$", a)  # 目测 \ 转义符和[]方括号等价
if ret:
    print("您输入的 %s 邮箱正确。正则匹配出来的是:%s " % (a, ret.group()))
else:
    print("您输入的 %s 邮箱错误!" % a)

# 但是,邮箱地址不止有163,还有QQ,139等等邮箱,上面的代码就不管用了
# 匹配分组
a = input("请输入您的邮箱地址:")
# 如果 . 符号没有加括号的话,那就成了匹配任意字符了,那么这里就要使用转义符 \ 来转义他为普通字符
# 如果在正则表达找那个,需要用到了某些普通的字符,比如 . ? * 等等,那么久要使用转义符了
# 当有多个邮箱地址只匹配其中一个的情况下,可使用 | 符号,等同价 or 匹配括号内任意表达式
ret = re.match(r"[a-zA-Z0-9_]{4,20}@(163|139|QQ)\.com$", a)  # 目测 \ 转义符和[]方括号等价
if ret:
    print("您输入的 %s 邮箱正确。正则匹配出来的是:%s " % (a, ret.group()))
else:
    print("您输入的 %s 邮箱错误!" % a)

# 在group()圆括号中,可以添加参数来提取使用的某一部分数据
# 比如下面填写1,因为数据只有一个QQ邮箱,所以提取出来的是QQ邮箱
ret = re.match(r"[a-zA-Z0-9_]{4,20}@(163|139|QQ)\.com$", "1654653@QQ.com").group(1)
print(ret)
# 如果想提取@前面的数据,只要加上()圆括号就可以了,圆括号里面的参数代表坐标,1个坐标就是第一个圆括号的数据,2就是第二个圆括号的数据,坐标如果超出了范围,就会报错
ret = re.match(r"([a-zA-Z0-9_]{4,20})@(163|139|QQ)\.com$", "1654653@QQ.com").group(1)
print(ret)

# 使用正则匹配网页代码
html_str = "<h1>hahaha</h1>"
# 正则中的\1就是取第一个圆括号里的值,就是说第一个圆括号里面的值是什么,那\1代表的就是什么
ret = re.match(r"<(\w*)>.*</\1>", html_str)
print(ret)
# 再添加多一个网页标签
html_str = "<body><h1>hahaha</h1></body>"
ret = re.match(r"<(\w*)><(\w*)>.*</\2></\1>", html_str)
print(ret)

# 如果分组过多的时候,可以给分组起名字,等价于上面的代码
html_str = "<body><h1>hahaha</h1></body>"
# 给分组起名字意思如下,给分组里面的值起名字,如<(?P<p1>\w*)>,给<(\w*)>起个名字叫p1,要在()括号里面以 ?P<名字> 格式,P是大写P
ret = re.match(r"<(?P<p1>\w*)><(?P<p2>\w*)>.*</(?P=p2)></(?P=p1)>", html_str)
print(ret)

# re的高级用法

print('*****************************************************************')
# search语法
# search和match语法不同的是,search不用从头开始匹配
ret = re.search(r"\d+", "阅读次数为 9999").group()  # 这句代码意思是,只匹配第一组数字
print(ret)
ret = re.search(r"\d+", "阅读次数为 9999,点赞数:100").group()  # 这句代码意思是,只匹配第一组数字
print(ret)  # 输出 9999

print('*****************************************************************')
# findall语法,直接匹配所有相关的数据
# 下面的代码意思是:直接返回数据里的所有数字,以列表的形式返回,不需要使用group()
ret = re.findall(r"\d+", "阅读次数为 9999,点赞数:100,观看次数:54")
print(ret)  # 输出['9999','100','54']

print('*****************************************************************')
# sub语法,将匹配到的数据进行替换,会将所有的数据都替换
# 下面的代码意思是:在数据中,将匹配到的所有数字都转换成998
ret = re.sub(r"\d+", "998", "99 = python = 9999")
print(ret)  # 输出 998 = python = 998


# 注意:sub语法可用在def函数中
def add(temp):
    strNum = temp.group()
    num = int(strNum) + 1
    return str(num)


# 下面的代码意思是:当正则匹配到了数据,会将数据当做实参返回给函数
ret = re.sub(r"\d+", add, "浏览量:998")
print(ret)

ret = re.sub(r"\d+", add, "点赞:1024")
print(ret)

print('*****************************************************************')
# split语法,根据匹配进行切割字符串,并返回一个列表
# 下面的代码意思是:将数据中含有:或者空格的,切割分开,并将数据以列表形式返回
ret = re.split(r":| ", "adds,ads:sdfadas sadfqwf qwfqwf 99")  # | 符号代表or
print(ret)  # 输出 ['adds,ads', 'sdfadas', 'sadfqwf', 'qwfqwf', '99']

# 下面的代码意思是:将数据中含有:或者空格或者,逗号的,切割分开,并将数据以列表形式返回
ret = re.split(r":|,| ", "adds,ads:sdfadas,sadfqwf qwfqwf 99")  # | 符号代表or
print(ret)  # 输出 ['adds', 'ads', 'sdfadas', 'sadfqwf', 'qwfqwf', '99']

# 练习,将没有用的东西剔除掉
html_str = '''<dd class="job_bt">
        <h3 class="description">职位描述:</h3>
        <div class="job-detail">
        <p>工作职责</p>
<p>1. 网站系统的维护、改进,以及新产品的开发;</p>
<p>2. 大型互联网web项目的设计、开发、优化。</p>
<p>&nbsp;</p>
<p>职位要求</p>
<p>1. 熟悉python, 熟悉mysql,有足够的互联网项目开发意识;</p>
<p>2. 熟悉linux, 熟悉git版本管理;</p>
<p>3. 各种分布式实现、中间件、数据挖掘、排序算法、搜索、运维...如果你有这些方面的经验和能力,千万不要忽略掉;</p>
<p>4. 有强烈的上进心和求知欲,善于学习和运用新知识, 保持对新技术的热情;</p>
        </div>
</dd>
'''

# print(html_str)

ret = re.sub(r'<(\w*|/\w*|.*")>', "", html_str)
print(ret)
print('-' * 40)
ret = re.sub(r'<(\w*|/\w*|.*)>', "", html_str)
print(ret)
# 上面两个表达式让我不解的是,为什么第一个表达式有 " 这个,第二个表达式没有 " 这个,为什么第二个表达式就把我的 职位描述这几个字给弄没了

 

posted @ 2019-10-24 14:37  John-Python  阅读(610)  评论(0编辑  收藏  举报