首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

十年python开发大牛总结的正则表达式

re模块

Python中通过re模块使用正则表达式,该模块提供的几个常用方法:

2.检索与替换

3.编译成Pattern对象

对于会多次用到的正则表达式,我们可以调用re的compile()方法编译成

Pattern对象,调用的时候直接Pattern对象.xxx即可,从而提高运行效率。

附:flags(可选标志位)表

python有趣吗?好玩吗?想学吗?这里小编创建了一个python学

习资料,欢迎想学习的小伙伴的加入,python有你更精彩!!嘿嘿!

多个标志可通过按位OR(|)进行连接,比如:re.I|re.M

2.正则规则详解

1.加在正则字符串前的'r'

为了告诉编译器这个string是个raw string(原字符串),不要转义反斜杠!

比如在raw string里\n是两个字符,''和'n',不是换行!

2.字符

3.数量

4.边界

5.分组

用()表示的就是要提取的分组,一般用于提取子串,

比如:^(\d)-(\d)$:从匹配的字符串中提取出区号和本地号码

附:group()方法与其他方法详解

不引入括号,增个表达式作为一个组,是group(0)

不引入()的话,代表整个表达式作为一个组,group = group(0)

如果引入()的话,会把表达式分为多个分组,比如下面的例子:

输出结果:

贪婪与非贪婪

正则匹配默认是贪婪匹配,也就是匹配尽可能多的字符。

比如:ret = re.match(r'^(\d+)(0*)$','12345000').groups()ß

我们的原意是想得到('12345','000')这样的结果,但是输出

ret我们看到的却是:

,由于贪婪,直接把后面的

0全给匹配了,结果0只能匹配空字符串了,如果想尽可能少的

匹配,可以在\d+后加上一个?问号采用非贪婪匹配,改成:

r'^(\d+?)(0)$',输出结果就变成了:

3.正则练习

例子1:简单验证手机号码格式

流程分析:

1.开头可能是带0(长途),86(天朝国际区号),17951(国际电话)中的一个或者一个也没有:

2.接着1xx,有13x,14x,15x,17x,18x,然后这个x也是取值范围也是不一样的:

14x:579

17x:01678

然后修改下正则表达式,可以随便输个字符串验证下:

3.最后就是剩下部分的8个数字了,很简单:[0-9] 加上:

^(0|86|17951)?(13[0-9]|14[579]|15[0-35-9]|17[01678]|18[0-9])[0-9]$

例子2:验证身份证

流程分析:

身份证号码分为一代和二代,一代由15位号码组成,而二代则是由18个号码组成:

十五位:xxxxxx yy mm dd pp s

十八位:xxxxxx yyyy mm dd ppp s

为了方便了解,把这两种情况分开,先是十八位的:

^[1-9]\d(18|19|20)\d(0[1-9]|10|11|12)([012][1-9]|10|20|30|31)\d[0-9Xx]|[1-9]\d\d(0[1-9]|10|11|12)([012][1-9]|10|20|30|31)\d[0-9Xx]$

另外,这里的正则匹配出的身份证不一定是合法的,判断身份是否

合法还需要通过程序进行校验,校验最后的校验码是否正确。

扩展阅读:身份证的最后一位是怎么算出来的?

更多可见:第二代身份证号码编排规则

首先有个加权因子的表:(没弄懂怎么算出来的..)

[7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]

然后位和值想乘,结果相加,最后除11求余,比如我随便网上找的

sum = 47 + 19 + 110 + 35 +88 + 1 4 ... + 6 * 2 = 282

sum % 11 = 7,所以这个是一个合法的身份证号。

例子3:验证ip是否正确

流程分析:

所以我们把第一段和后面三段分开,然后分析下ip的结构,可能是这几种情况:

一位数:[1-9]

两位数:[1-9][0-9]

三位数(100-199):1[0-9][0-9]

三位数(200-249):2[0-4][0-9]

三位数(250-255): 25[0-5]

理清了第一段的正则怎么写就一清二楚了:

^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]))$

4.正则实战

实战:抓一波城市编码列表

本来想着就抓抓中国气象局的天气就好了,然后呢,比如深圳天气的网页是:

然后这个101280601是城市编码,然后网上搜了下城市编码列表,发现要么

很多是错的,要么就缺失很多,或者链接失效,想想自己想办法写一个采集

的,先搞一份城市编码的列表,不过我去哪里找数据来源呢?中国气象局

肯定是会有的,只是应该不会直接全部暴露出来,想想能不能通过一些间接

操作来实现。对着中国气象局的网站瞎点,结果不负有心人,我在这里:

发现了这个:

然后,我觉得这可能是入手点:

这里有个超链接,难不成是北京所有的地区的列表,点击下进去看看:

卧槽,果然是北京所有的地区,然后每个地区的名字貌似都有一个超链接

F12看下指向哪里?

到这里就豁(huo)然开朗了,我们来捋一捋实现的流程:

1.先拿到第一层的城市列表链接用列表存起来

2.接着遍历列表去访问不同的城市列表链接,截取不同城市的城市名,城市编码存起来

流程看上去很简单,接着来实操一波。

先是拿城市列表url

接着随便点开一个,比如beijing.shtml,页面结构是这样的:

想要的内容是这里的超链接:

F12看下页面结构,层次有点多,不过没关系,这样更能够锻炼我们

入手点一般都是离我们想要数据最近地方下手,我看上了:conMidtab3

全局搜了一下,也就八个:

第一个直接就可以排除了:

是我们想要的内容,接着里面的tr是我们需要内容,找一波:

输出下:

重复出现了一堆详情,很明显是我们不想要的,我们可以在循环的时候

执行一波判断,重复的不加入到列表中:

城市的话还好,直接调用tag对象的string直接就能拿到,

而城市编码的话,按照以前的套路,我们需要先['href']拿到

再做字符串裁剪,挺繁琐的,既然本节学习了正则,为何不用

正则来一步到位,不难写出这样的正则:

卧槽,就是我们想要的结果,美滋滋,接着把之前拿到所有

的城市列表都跑一波,存字典里返回,最后赛到一个大字典

里,然后写入到文件中,完成。

========= BUG的分割线 =========

最后把数据打印出来发现只有428条数据,后面才发现conMidtab3那里处理有些

问题,漏掉了一些,限于篇幅,就不重新解释了,直接贴上修正完后的代码把...

import urllib.request

from urllib import error

from bs4 import BeautifulSoup

import os.path

import re

import operator

# 通过中国气象局抓取到所有的城市编码

# 中国气象网基地址

# 华北天气预报url

weather_hb_url = "http://www.weather.com.cn/textFC/hb.shtml#"

# 获得城市列表链接

def get_city_list_url():

city_list_url = []

weather_hb_html = weather_hb_resp.read().decode('utf-8')

weather_hb_soup = BeautifulSoup(weather_hb_html, 'html.parser')

weather_box = weather_hb_soup.find(attrs={'class': 'lqcontentBoxheader'})

weather_a_list = weather_box.findAll('a')

for i in weather_a_list:

city_list_url.append(weather_base_url + i['href'])

return city_list_url

# 根据传入的城市列表url获取对应城市编码

def get_city_code(city_list_url):

city_code_dict = {} # 创建一个空字典

city_pattern = re.compile(r'^$') # 获取城市编码的正则

weather_hb_html = weather_hb_resp.read().decode('utf-8')

weather_hb_soup = BeautifulSoup(weather_hb_html, 'html.parser')

# 需要过滤一波无效的

div_conMidtab = weather_hb_soup.find_all(attrs={'class': 'conMidtab', 'style': ''})

for mid in div_conMidtab:

tab3 = mid.find_all(attrs={'class': 'conMidtab3'})

for tab in tab3:

trs = tab.findAll('tr')

for tr in trs:

a_list = tr.findAll('a')

for a in a_list:

if a.get_text() != "详情":

# 正则拿到城市编码

city_code = city_pattern.match(str(a)).group(1)

city_name = a.string

city_code_dict[city_code] = city_name

return city_code_dict

# 写入文件中

def write_to_file(city_code_list):

try:

with open('city_code.txt', "w+") as f:

for city in city_code_list:

f.write(city[0] + ":" + city[1] + "\n")

except OSError as reason:

print(str(reason))

else:

print("文件写入完毕!")

if __name__ == '__main__':

city_result = {} # 创建一个空字典,用来存所有的字典

city_list = get_city_list_url()

# get_city_code("http://www.weather.com.cn/textFC/guangdong.shtml")

for i in city_list:

print("开始查询:" + i)

city_result.update(get_city_code(i))

# 根据编码从升序排列一波

sort_list = sorted(city_result.items(), key=operator.itemgetter(0))

# 保存到文件中

write_to_file(sort_list)

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180105A0JATM00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券