# -*- 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位数字,等价于[0-99],也可以写{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> </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) # 上面两个表达式让我不解的是,为什么第一个表达式有 " 这个,第二个表达式没有 " 这个,为什么第二个表达式就把我的 职位描述这几个字给弄没了