1.正则表达式
1.1.什么是正则表达式
正则表达式,又称规则表达式(Regular Expression,在代码中常简写为regex、regexp或RE),正则表达式描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与运算符可以将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。
正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
总之,正则表达式通常用来检索、替换符合规则的文本。
1.2.组成
-
原子: 普通字符,如英文字符
-
元字符:有特殊功能的字符
一个正则表达式至少有一个原子组成
1.3.常见的正则字符和含义
-
匹配单个字符
正则字符 | 含义 |
---|---|
. | 匹配任意一个字符,除了换行符 |
[] | 匹配 [ ] 中列举的字符。例如:[abc]、[a-z] |
\s | 匹配空白字符,即:空格、换行、Tab符 |
\S | 匹配任何非空白字符 |
\d | 匹配数字,等价于[0-9] |
\D | 匹配非数字,等价于[^0-9] |
\w | 匹配字母数字下划线,等价于[A-Za-z0-9_] |
\W | 匹配非字母数字下划线,等价于[^A-Za-z0-9_] |
-
匹配多个字符
正则字符 | 含义 |
---|---|
* | 匹配前一个字符出现0次或多次,即:可有可无 |
+ | 匹配前一个字符出现1次或多次,即:至少有一次 |
? | 匹配前一个字符出现0次或1次,即:要么一次,要么没有 |
{m} | 匹配前一个字符出现m次 |
{m,n} | 匹配前一个字符出现从m到n次 |
-
匹配开头结尾
正则字符 | 含义 |
---|---|
^在[]外 | 匹配字符串开头 |
^在[]内 | 取反 |
$ | 匹配字符串末尾 |
-
匹配分组
正则字符 | 含义 |
---|---|
| | 匹配左右任意一个表达式 |
() | 将括号中字符作为一个分组 |
\num | 引用分组num匹配到的字符串 |
起别名 | 定义:(?P<name1> 正则表达式) 引用:(?P=name1) |
1.4.综合案例
# 1)匹配首字母大写的字符(注:后面字符任意,并且可有可无) # 2)0-99的数字 # 3)匹配出:不是以4结尾的手机号码11位 # 4)匹配出:8到20位的密码,可以是大小写英文字母、数字、下划线 # 5)匹配出:163邮箱,且@符号之前有4到20位 # 注意:.在此处有特殊意义,需转义处理\. # 6)匹配出:匹配字符串,必须字母下划线开头(数字不行)
2.re模块
re
是Python标准库中的一个模块,用于进行正则表达式匹配和操作。正则表达式是一种强大的模式匹配工具,可以用于在字符串中进行搜索、替换和分割操作。
要使用re
模块,首先需要导入它:
import re
re
模块提供了一系列函数和常量,用于处理正则表达式。
2.1re常用的函数和方法:
在Python中,可以使用re
模块来创建正则表达式对象并进行匹配、查找、替换等操作。re
模块提供了许多函数和方法,包括:
-
re.search(pattern, string, flags=0)
:在字符串中搜索并返回第一个匹配的结果对象。可以指定可选的flags
参数来修改匹配的行为。 -
re.match(pattern, string, flags=0)
:从字符串的开头开始匹配,如果匹配成功则返回结果对象,否则返回None
。 -
re.findall(pattern, string, flags=0)
:返回所有与正则表达式匹配的非重叠结果的列表。 -
re.sub(pattern, repl, string, count=0, flags=0)
:使用repl
替换字符串中与正则表达式匹配的部分。可选的count
参数用于指定最多替换次数。
其中,pattern
是正则表达式字符串,string
是要匹配的字符串,flags
是用于控制正则表达式的匹配行为的标志,repl
是替换字符串,count
是最多替换的次数。匹配对象是一个包含匹配的信息的特殊对象,可以用来获取匹配的子串、位置等信息。
注意,match和search的返回结果方法有:
方法 | 含义 |
---|---|
group() | 返回被re匹配的字符串 |
start() | 返回匹配的开始位置 |
end() | 返回匹配的结束位置 |
span() | 返回一个元组包含匹配(开始,结束)的位置 |
2.2案例
案例一:电子邮箱验证
# qq邮箱验证 match = "\d{4,10}@qq\.com" email = "529503476@qq.com" m = re.match(match, email) if m: print("有效的QQ邮箱") else: print("无效的QQ邮箱")
案例二:findall和finditer查找字符串中所有匹配的子串
st = "aa123asd123asd134ada123" # 注意:这里需要使用()进行分组处理 all = re.findall('(\d+)', st) print(all)
# finditer返回为迭代器,需要遍历 matchs = re.finditer(pattern,st) for match in matchs: print(match.group())
案例三:search在字符串中查询第一个匹配的位置
st = "aa123asd123asd134ada123" search = re.search('(\d+)', st) print(search) print("返回被re匹配的字符串:",search.group()) print("返回匹配的开始位置:",search.start()) print("返回匹配的结束位置:",search.end()) print("返回一个元组包含匹配(开始,结束)的位置:",search.span())
案例四:使用sub实现正则替换
HA:被替换的对象
st字符串
count:替换前面2个符合的
st = "aa123asd123asd134ada123" sub = re.sub('(\d+)', 'HA', st, count=2) print(sub)
3.贪婪与非贪婪
在Python中,正则表达式(re)模块支持贪婪(greedy)和非贪婪(non-greedy)匹配模式。贪婪匹配尽可能匹配更多的字符,而非贪婪匹配尽可能匹配更少的字符。
在匹配字符后面添加?,匹配非贪婪模式。
使用RegexBuddy工具进行贪婪与非贪婪规则校验,待校验字符串如下:
<img src="https://img.xx.a" title="美女图片"/> <img src="http://img.xx.a" title="美女图片"/> <img src="/img.xx.a" title="美女图片"/>
请使用正则验证img标签中的src属性,并结合贪婪与非贪婪。
通过re
模块中的findall提取上述字符串中的src属性值,例如:
# 贪婪与非贪婪 st = """ <img src="https://img.xx.a" title="美女图片"/> <img src="http://img.xx.a" title="美女图片"/> <img src="/img.xx.a" title="美女图片"/> """ # 通过re模块中的findall提取上述字符串中的src属性值 # 非贪婪 all = re.findall(r'src="(.+?)"', st) print(all) # 贪婪 all = re.findall(r'src="(.+)"', st) print(all)
个人总结:贪婪模式会取到最后一个双引号,而非贪婪模式会在第一个双引号停止
正则字符串前面加上"r"表示:让正则中的“\”不再具有转义功能。
4.热词搜索
这里采用的是某网站的地址进行的案例演示。
import requests, re # 导入必要的库
from pathlib import Path # 导入路径操作相关的库
from urllib.request import urlretrieve # 导入下载文件相关的库
headers = { # 设置请求头
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36 Edg/125.0.0.0"
}
resp = requests.get('https://www.dianping.com/', headers=headers) # 发起 GET 请求
resp.encoding = 'utf-8' # 设置响应的编码为 UTF-8
findall = re.findall(r'<img lazy-src="(.+?)"', resp.text) # 在响应文本中查找所有匹配的图片链接
for e in findall: # 遍历每个找到的图片链接
path = Path(e) # 创建 Path 对象,用于处理文件路径
urlretrieve(e, "./大众点评/" + path.name) # 下载图片到指定路径,并用原始文件名命名
记得建一个大众点评文件夹
5.词频统计
5.0英文词频统计
# 使用自己构建的字典来统计单词出现的次数
text = "The early bird catches the worm."
words = text.lower().split() # 将文本转换为小写,并按空格分割为单词列表
word_counts = {} # 初始化一个空字典,用于存储单词出现的次数
for word in words: # 遍历每个单词
if word in word_counts: # 如果单词已经在字典中
word_counts[word] += 1 # 增加该单词出现的次数
else:
word_counts[word] = 1 # 否则将单词添加到字典中,并设置出现次数为1
print(word_counts) # 打印统计结果
# 使用 collections 模块中的 Counter 类来统计单词出现的次数
from collections import Counter
text = "The early bird catches the worm."
words = text.lower().split() # 将文本转换为小写,并按空格分割为单词列表
word_counts = Counter(words) # 使用 Counter 类统计单词出现的次数
for word, count in word_counts.items(): # 遍历 Counter 对象的键值对
print(word, count) # 打印单词及其出现的次数
5.1.jieba库
jieba
是一个流行的中文分词库,用于将中文文本按词语进行分割。它是基于统计方法和词频字典构建的字典分词模型。jieba
库提供了多种分词模式和功能,可以用于中文文本的分词、关键词提取等自然语言处理任务。
请先下载jieba库,该库下载比较慢,请耐心等待。
安装完成后,你可以在Python脚本中导入jieba
库:
import jieba
-
入门示例:
import jieba st = "我在梅溪湖洗脚按摩大保健" words = jieba.cut(st) print(list(words))
-
加载自定义的词库:
请先在当前python项目目录下创建cy.txt文本文件,并添加你所认为的词,例如:“梅溪湖”
import jieba # 加载自定义的词库 jieba.load_userdict("cy.txt") st = "我在梅溪湖洗脚按摩大保健" words = jieba.cut(st) print(list(words))
-
匹配模式(精准和全模式):
import jieba st = "我在岳麓山洗澡,做头发" # 精准模式:把出现的词放到列表中 words = jieba.cut(st) print(list(words)) # 全模式:把可能出现的词组,都放入列表 words = jieba.cut(st,cut_all=True) print(list(words))
通过
cut_all=True
设定全模式匹配。
5.2.热搜词频统计
微博热搜地址:微博 热搜榜 今日热榜
操作步骤:
-
先通过
requests
模块爬取微博热搜中的所有网页内容 -
通过
re
模块中的findall
查找所有与之匹配的结果 -
针对结果使用逗号将匹配到的结果拼接起来,然后再使用
jieba
库的全模式匹配 -
筛选出符合条件的词条结果,并进行词频统计
import requests,re,jieba headers = { "user-agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36' } # verify = false 表示不进行安全校验 resp = requests.get('https://tophub.today/n/KqndgxeLl9', headers=headers, verify=False) resp.encoding = "UTF-8" # # print(resp.text) findall = re.findall(r'<a href="/l\?e=.+?" target="_blank" rel="nofollow" itemid="\d+">(.+?)</a>', resp.text) print(findall) # 使用逗号将匹配到的结果拼接起来,然后再使用全模式匹配 cs = jieba.lcut(",".join(findall), cut_all=True) # 两个字才能算是词 cs = list(filter(lambda a: len(a)>1,cs)) print(cs) # 词频统计 import collections cn = collections.Counter(cs) print(cn)