一、re模块和正则表达式
先来看一个例子:https://reg.jd.com/reg/person"htmlcode">
# 方式一 判断号码是否合法 # -*- coding:utf-8 -*- while True: phone_number = str(input('please input your phone number : ')) if len(phone_number) == 11 and phone_number.isdigit() and (phone_number.startswith('13') or phone_number.startswith('14') or phone_number.startswith('15') or phone_number.startswith('18')): print('是合法的手机号码') else: print('不是合法的手机号码')
# 方式二 判断号码是否合法 # -*- coding:utf-8 -*- import re phone_number = str(input('please input your phone number : ')) if re.match('^(13|14|15|18)[0-9]{9}$',phone_number): print('是合法的手机号码') else: print('不是合法的手机号码')
正则表达式不仅在python领域,在整个编程届都占有举足轻重的地位。
不管以后你是不是去做python开发,只要你是一个程序员就应该了解正则表达式的基本使用。如果未来你要在爬虫领域发展,你就更应该好好学习这方面的知识。
但是你要知道,re模块本质上和正则表达式没有关系。re模块和正则表达式的关系 类似于time模块和时间的关系。
时间有自己的格式,年月日时分秒,12个月,365天......已经成为了一种规则。
正则表达式本身也和python没有什么关系,就是匹配字符串内容的一种规则。
官方定义:正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
二、正则表达式
在线测试工具 http://tool.chinaz.com/regex/
首先谈到正则,就只和字符串相关了。在我给你提供的工具中,你输入的每一个字都是一个字符串。
其次,如果在一个位置的一个值,不会出现什么变化,那么是不需要规则的。
比如你要用"1"去匹配"1",或者用"2"去匹配"2",直接就可以匹配上。这连python的字符串操作都可以轻松做到。
那么在之后我们更多要考虑的是在同一个位置上可以出现的字符的范围。
2.1 字符组
字符组 : [字符组]
在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[]表示
字符分为很多类,比如数字、字母、标点等等。
假如你现在要求一个位置"只能出现一个数字",那么这个位置上的字符只能是0、1、2...9这10个数之一。
结果 说明 [0123456789] 8 True 在一个字符组里枚举合法的所有字符,字符组里的任意一个字符
和"待匹配字符"相同都视为可以匹配 [0123456789] a False 由于字符组中没有"a"字符,所以不能匹配 [0-9] 7 True 也可以用-表示范围,[0-9]就和[0123456789]是一个意思 [a-z] s True 同样的如果要匹配所有的小写字母,直接用[a-z]就可以表示 [A-Z] B True [A-Z]就表示所有的大写字母 [0-9a-fA-F] e True 可以匹配数字,大小写形式的a~f,用来验证十六进制字符
2.2 元字符
元字符 匹配内容 . 匹配除换行符以外的任意字符 \w 匹配字母或数字或下划线 \s 匹配任意的空白符 \d 匹配数字 \n 匹配一个换行符 \t 匹配一个制表符 \b 匹配一个单词的结尾 ^ 匹配字符串的开始 $ 匹配字符串的结尾 \W 匹配非字母或数字或下划线 \D 匹配非数字 \S 匹配非空白符 a|b 匹配字符a或字符b () 匹配括号内的表达式,也表示一个组 [...] 匹配字符组中的字符 [^...] 匹配除了字符组中字符的所有字符2.3 量词
量词 用法说明 * 重复零次或更多次 + 重复一次或更多次 "小."的字符 ^小. 小明小军小兰 小明 只从开头匹配"小." 小.$ 小明小军小兰 小兰 只匹配结尾的"小.$"2.3.2 * + "小"后面一个任意字符 小.* 小明和小李子和小巧玲珑 小明和小李子和小巧玲珑 *表示重复零次或多次,即匹配"小"后面0个或多个任意字符 小.+ 小明和小李子和小巧玲珑 小明和小李子和小巧玲珑 +表示重复一次或多次,即只匹配"小"后面1个或多个任意字符 小.{1,2} 小明和小李子和小巧玲珑
小明和
小李子
小巧玲
注意:前面的*,+,"小"字后面[明李子巧玲珑]的字符任意次 小[^和]* 小明和小李子和小巧玲珑
小明
小李子
小巧玲珑
4
5
6
3
456
3
2.5 分组 ()与 或 |[^]
身份证号码是一个长度为15或18个字符的字符串,如果是15位则全部由数字组成,首位不能为0;如果是18位,则前17位全部是数字,末位可能是数字或x,下面我们尝试用正则来表示:
正则 待匹配字符 匹配结果 说明 ^[1-9]\d{13,16}[0-9x]$ 110101198001017032
110101198001017032
表示可以匹配一个正确的身份证号 ^[1-9]\d{13,16}[0-9x]$ 11010119800101701101011980010170
表示也可以匹配这串数字,但这并不是一个正确的身份证号码,它是一个
16位的数字 ^[1-9]\d{14}(\d{2}[0-9x])"\d"而不是"数字"就需要对"\"进行转义,变成'\\'。
在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中\也有特殊的含义,本身还需要转义。所以如果匹配一次"\d",字符串中要写成'\\d',那么正则里就要写成"\\\\d",这样就太麻烦了。
这个时候我们就用到了r'\d'这个概念,此时的正则是r'\\d'就可以了。
正则 待匹配字符 匹配结果 说明 \d \d False 因为在正则表达式中\是有特殊意义的字符,所以要匹配\d本身,用表达式\d无法匹配 \\d \d True 转义\之后变成\\,即可匹配 "\\\\d" '\\d' True 如果在python中,字符串中的'\'也需要转义,所以每一个字符串'\'又需要转义一次 r'\\d' r'\d' True 在字符串之前加r,让整个字符串不转义
2.7 贪婪匹配
贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配
正则 待匹配字符 匹配结果 说明 <.*>
<script>...<script>
<script>...<script> 默认为贪婪匹配模式,会匹配尽量长的字符串 <.*"htmlcode">import re ret = re.findall('a', 'ea eg an') # 返回所有满足匹配条件的结果,放在列表里 print(ret) #结果 : ['a', 'a'] ret = re.search('a', 'va eg an').group() print(ret) #结果 : 'a' # 函数会在字符串内查找模式匹配,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以 # 通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。 ret = re.match('a', 'abc').group() # 同search,不过尽在字符串开始处进行匹配 print(ret) #结果 : 'a' ret = re.split('[ab]', 'abcd') # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割 print(ret) # ['', '', 'cd'] ret = re.sub('\d', 'H', 'va3eg4an4', 1)#将数字替换成'H',参数1表示只替换1个 print(ret) #vaHeg4an4 ret = re.subn('\d', 'H', 'va3eg4an4')#将数字替换成'H',返回元组(替换的结果,替换了多少次) print(ret) obj = re.compile('\d{3}') #将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字 ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串 print(ret.group()) #结果 : 123 import re ret = re.finditer('\d', 'ds3sy4784a') #finditer返回一个存放匹配结果的迭代器 print(ret) # <callable_iterator object at 0x10195f940> print(next(ret).group()) #查看第一个结果 print(next(ret).group()) #查看第二个结果 print([i.group() for i in ret]) #查看剩余的左右结果
注意:
1 findall的优先级查询:
import re ret = re.findall('www.(baidu|xunlei).com', 'www.xunlei.com') print(ret) # ['xunlei'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可 ret = re.findall('www.("htmlcode">ret=re.split("\d+","va3eg4an") print(ret) #结果 : ['va', 'eg', 'an'] ret=re.split("(\d+)","va3eg4an") print(ret) #结果 : ['va', '3', 'eg', '4', 'an'] #在匹配部分加上()之后所切出的结果是不同的, #没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项, #这个在某些需要保留匹配部分的使用过程是非常重要的。3.1 匹配标签
import re ret = re.search("<(","<h1>hello</h1>") #还可以在分组中利用"<(\w+)>\w+</\1>","<h1>hello</h1>") #如果不给组起名字,也可以用\序号来找到对应的组,表示要找的内容和前面的组内容一致 #获取的匹配结果可以直接用group(序号)拿到对应的值 print(ret.group(1)) print(ret.group()) #结果 :<h1>hello</h1>2、匹配整数
import re ret=re.findall(r"\d+","1-2*(60+(-40.35/5)-(-4*3))") print(ret) #['1', '2', '60', '40', '35', '5', '4', '3'] ret=re.findall(r"-","1-2*(60+(-40.35/5)-(-4*3))") print(ret) #['1', '-2', '60', '', '5', '-4', '3'] ret.remove("") print(ret) #['1', '-2', '60', '5', '-4', '3']3、数字匹配
1、 匹配一段文本中的每行的邮箱
http://blog.csdn.net/make164492212/article/details/516566382、 匹配一段文本中的每行的时间字符串,比如:‘1990-07-12';
分别取出1年的12个月(^(0"htmlcode">import requests import re import json def getPage(url): response=requests.get(url) return response.text def parsePage(s): com=re.compile('<div class="item">.*"pic">.*"title">("rating_num" .*"id":i.group("id"), "title":i.group("title"), "rating_num":i.group("rating_num"), "comment_num":i.group("comment_num"), } def main(num): url='https://movie.douban.com/top250"move_info7","a",encoding="utf8") for obj in ret: print(obj) data=json.dumps(obj,ensure_ascii=False) f.write(data+"\n") if __name__ == '__main__': count=0 for i in range(10): main(count) count+=25简化版
import re import json from urllib.request import urlopen def getPage(url): response = urlopen(url) return response.read().decode('utf-8') def parsePage(s): com = re.compile( '<div class="item">.*"pic">.*"title">("rating_num" .*"id": i.group("id"), "title": i.group("title"), "rating_num": i.group("rating_num"), "comment_num": i.group("comment_num"), } def main(num): url = 'https://movie.douban.com/top250"move_info7", "a", encoding="utf8") for obj in ret: print(obj) data = str(obj) f.write(data + "\n") count = 0 for i in range(10): main(count) count += 25flags有很多可选值:
re.I(IGNORECASE)忽略大小写,括号内是完整的写法
re.M(MULTILINE)多行模式,改变^和$的行为
re.S(DOTALL)点可以匹配任意字符,包括换行符
re.L(LOCALE)做本地化识别的匹配,表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境,不推荐使用
re.U(UNICODE) 使用\w \W \s \S \d \D使用取决于unicode定义的字符属性。在python3中默认使用该flag
re.X(VERBOSE)冗长模式,该模式下pattern字符串可以是多行的,忽略空白字符,并可以添加注释实现能计算类似
1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等类似公式的计算器程序
python,re模块
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。