目录
(ABC)、[ABC]、[A|B|C]、[(ABC)]的区别
简介
正则表达式(Regular Expression)是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。
re 模块使 Python 语言拥有全部的正则表达式功能。
正则表达式常用字符
你可能没有了解过正则表达式,但却已经用过了部分。比如使用 rm -rf *.txt来删除所有.txt后缀的文件,*就是正则表达式中的符号之一。
定位符
定位符 | 说明 | 正则表达式举例说明 |
^ | 匹配字符串的开始,除非在方括号表达式中使用,当该符号在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合。 | 方括号表达式中的使用,请查看字符组一节 |
$ | 匹配字符串的结尾,如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n' 或 '\r'。 | 使用修饰符s时可包含换行符"\n" |
\b | 匹配一个单词边界,即字与空格间的位置。 | \bhello,可以匹配hello |
\B | 非单词边界匹配。 | \Bllo,可以匹配hello中的llo |
元字符
元字符 | 说明 | 正则表达式举例说明 |
. | 匹配任何字符(换行符除外) | "."可匹配"@" |
\d | 匹配数字,等价于 [0-9] | "\d"可匹配"9" |
\D | 匹配一个非数字字符,等价于 [^0-9]。 | "\D"可匹配"a" |
\w | 匹配字母、数字、下划线,等价于'[A-Za-z0-9_]'。前提是设置了ASCII 标志。 | "\w"可匹配"_" |
\W | 匹配非字母、数字、下划线,等价于 '[^A-Za-z0-9_]'。 | "\W"可匹配"" |
\f | 匹配一个换页符。等价于 \x0c 和 \cL。 | |
\n | 匹配一个换行符。等价于 \x0a 和 \cJ。 | |
\r | 匹配一个回车符。等价于 \x0d 和 \cM。 | |
\t | 匹配一个制表符。等价于 \x09 和 \cI。 | |
\v | 匹配一个垂直制表符。等价于 \x0b 和 \cK。 | |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 | |
\S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 | |
\ | 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。 | "\$"匹配"$" |
修饰符
修饰符 | 含义 | 描述 |
---|---|---|
i | ignore - 不区分大小写 | 将匹配设置为不区分大小写,搜索时不区分大小写: A 和 a 没有区别。 |
g | global - 全局匹配 | 查找所有的匹配项。 |
m | multi line - 多行匹配 | 使边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾。 |
s | 特殊字符圆点 . 中包含换行符 \n | 默认情况下的圆点 . 是 匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n。 |
字符组
字符组 | 说明 | 举例 | 举例说明 |
---|---|---|---|
[...] | 匹配字符组里出现的任意一个字符 | [123abc] | |
[字符1-字符2] | 匹配从字符1到字符2的所有字符 | [0-9]、[a-z] | 匹配一个数字/英文小写字母 |
[^字符1-字符2] | 匹配未包含的任意字符。 | [^0-9]、[^a-z] | 匹配不包含数字/英文小写字母的一个字符 |
(正则表达式) | 匹配()内的正则表达式,可用于多个字符打包 | \d+(\.\d+)? | 简单浮点型(),一到多个数字,小数点,一到多个数字, |
重复限定符
重复限定符 | 说明 | 正则表达式样例 |
---|---|---|
* | 重复零次或更多次 | hello!*可匹配hello!!!!等 |
+ | 重复一次或更多次 | hello!+可匹配hello!等 |
? | 重复零次或一次 | hello!?可匹配hello、hello! |
{M,N} | 匹配前面出现的正则表达式M到N次 | [1-9][0-9]{1,2}可匹配二、三位整数 |
{N} | 匹配前面出现的正则表达式N次 | [1-9][0-9]{1}可匹配两位整数 |
{N,} | 匹配前面出现的正则表达式至少N次 | [1-9][0-9]{1}可匹配两位及以上整数 |
注意:不能将限定符与定位符一起使用。
re模块
函数 | 说明 |
---|---|
match(pattern, string, flags=0) | 尝试用正则表达式模式pattem 匹配字符串string,flags 是可选标识符,如果匹配成功,则返回一个匹配对象:否则返回None |
search(pattern, string, flags=0) | 在字符串string 中搜索正则表达式模式patterm的第一次出现,flags 是可选标识符,如果匹配成功,则返回一个匹配对象:否则返回None |
sub(pattern, repl, string, count=0, flags=0) | 把字符串string中所有匹配正则表达式patterm的地方替换成字符串repl,如果max的值没有给出,则对所有匹配的地方进行替换(另外,请参考subn(),它还会返回-一个表示替换次数的数值) |
findall(string[, pos[, endpos]]) | 在字符串string中搜索正则表达式模式pattemn的所有(非重复)出现:返回一个匹配对象的列表 |
finditer(pattern, string, flags=0) | 和findall0相同,但返回的不是列表而是迭代器:对于每个匹配,该迭代器返回一一个匹配对象 |
split(pattern, string[, maxsplit=0, flags=0]) | 根据正则表达式pattem中的分隔符把字符string分割为-个列表,返回成功匹配的列表,最多分割max次(默认是分割所有匹配的地方) |
匹配对象的方法 | |
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。 |
手机号判断
貌似就是第二位没有2,其他的也没什么。
# 手机号
def phone_number():
pattern = r'^1[3456789]\d{9}$'
pho_number = '15732118829'
res = re.match(pattern, pho_number)
return res
昵称判断
假设昵称规则是数字,英文字母,下划线,不允许数字开头。
# 昵称 英文字母、数字、下划线
def nick_name():
pattern = r'^[^\d]\w+$'
pho_number = 'hbhWFEFf_哈哈'
res = re.match(pattern, pho_number)
return res
b站弹幕礼仪
1、不要轻易提及其他up主
2、不要用弹幕去挡字幕
3、杜绝毫无意义的刷屏
4、杜绝主观评价
5、不要用弹幕与人辩论和争吵
6、不要发一般人看不懂的外语
7、杜绝剧透
8、杜绝无意义低俗空耳
9、不要在弹幕提及个人信息
10、尽量避免长篇大论
11、不要在弹幕问无脑问题
12、不要发年月日期
来源:22娘关于弹幕礼仪的总结性讲演_哔哩哔哩_bilibili
b站弹幕屏蔽正则
长弹幕
屏蔽字数长度超过20的弹幕,不懂编程的小伙伴就改里面的数字就好。
/.{20,}/
个人信息
手机号
屏蔽国内11位手机号
/^1[3456789]\d{9}$/
QQ号
屏蔽腾讯QQ号,10000开始,目前11位。
/[1-9][0-9]{4,8}/
日期
屏蔽2-4位的年,1-2位的月,1-2位的日,使用汉字、“.”、“-”连接。例如,2020年8月9日,2020.8.10,20-8-11等。
/^\d{2,4}[年|\-|\.]\d{1,2}[月|\-|\.]\d{1,2}[日|号|.]*$/
无意义
现场怪
屏蔽类似:在现场、我在现场、当时在现场、才发现在现场这些弹幕
/^.*在现场$/
视频顺序
屏蔽类似:第一、第二个、前三、第5这些弹幕
/^(第|前)[零一二两俩三四五六七八九十\d]个?$/
开心
2后面多个3表示开心
/^23+$/
多个字重复,多个哈,多个6等,可以自行添加在后面[]中
/^[哈呵哼6xswlawsl]+嗝?$/
有哪些想要屏蔽的弹幕可以下方评论,如有时间我会编写正则并回复。
要求:
1.能够总结出规律
2.误杀率低
代码
import re
# 手机号
def phone_number():
pattern = r'^1[3456789]\d{9}$'
pho_number = '15732118829'
res = re.match(pattern, pho_number)
return res
# 昵称 英文字母、数字、下划线
def nick_name():
pattern = r'^[^\d]\w+$'
pho_number = 'hbhWFEFf_哈哈'
res = re.match(pattern, pho_number)
return res
def date1():
pattern = r'^\d{2,4}[年|\-|\.]\d{1,2}[月|\-|\.]\d{1,2}[日|号|.]*$'
# bullet = '2020.08.10'
# bullet = '2020-08-10'
# bullet = '20-08-10'
# bullet = '2020年8月10日'
bullet = '2020年08月10号'
print(bullet)
res = re.match(pattern, bullet)
return res
def tooLong():
pattern = r"^.{20,}$"
# bullet = '短弹幕短弹幕短弹幕短弹幕短弹幕'
bullet = '长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕长弹幕'
print(bullet)
res = re.match(pattern, bullet)
return res
def QQ():
pattern = r"[1-9][0-9]{4,8}"
# bullet = '1000'
bullet = "1187276773"
print(bullet)
res = re.match(pattern, bullet)
return res
def happy():
pattern = r"^[哈呵哼6xswlawsl]+嗝?$"
# bullet = "666666"
# bullet = "哈哈哈哈"
# bullet = "哈哈哈嗝"
bullet = "awslawslawsl"
print(bullet)
res = re.match(pattern, bullet)
return res
def shunxu():
pattern = r"^(第|前)?[零一二两俩三四五六七八九十\d]+个?$"
# bullet = "第二"
# bullet = "前三"
# bullet = "第二个"
# bullet = "第5"
bullet = "前三"
print(bullet)
res = re.match(pattern, bullet)
return res
def xianchang():
pattern = r"^.*在现场$"
# bullet = "在现场"
# bullet = "我在现场"
bullet = "当时在现场"
print(bullet)
res = re.match(pattern, bullet)
return res
if __name__ == "__main__":
# res = phone_number()
# if res:
# print('手机号注册成功!')
# else:
# print('请输入正确的手机号!')
# ans = nick_name()
# if ans:
# print('账号注册成功!')
# else:
# print('账号不符合规则!')
# ans = date1()
# ans = tooLong()
# ans = QQ()
# ans = happy()
# ans = shunxu()
ans = xianchang()
if ans:
print('已屏蔽')
else:
print('无法屏蔽')
未完待续...
ps:为写本文,收集了弹幕,制作了两个视频
播放量太惨了,一首《凉凉》送给自己,逛b站的粉丝们去看下上面两个视频呗,十分感谢!
------------------2022-03-26更新--------------------
(ABC)、[ABC]、[A|B|C]、[(ABC)]的区别
()里面是正则表达式,只有ABC的时候才能匹配,不会匹配A、B、AB、BC之类的
[]是匹配任意一个,也就是匹配A、B、C,AB、ABC之类的不会匹配
这个是一种手误,或者有些人为了区分前两个,故意这样写的。会多匹配一个“|”,一般没什么影响
这种想法是想把 你好 作为一个进行匹配,但是和上面一样,会匹配(、你、好、),并不会匹配你好,想要匹配汉字词组,可以使用(()|())
-----------------2022-03-26更新完毕---------------
在线工具
可视化正则
Regulex:JavaScript Regular Expression Visualizer
通过上面的网站,可以更方便的写正则。
在线匹配
Regex Tester - Javascript, PCRE, PHP
上面的在线匹配应该是不行了,换一个:菜鸟正则测试
高级篇
非获取匹配/非捕获组(Non-Capturing Group)
(?:pattern) 非获取匹配,匹配pattern但不获取匹配结果,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分是很有用。
例如,lady_killer9|lady_killers可以写成lady_killer(?:9|s)
零宽断言(Zero-Width Assertion)
(?=pattern) 非获取匹配,正向肯定预查,匹配后面是pattern的数据,该匹配不需要获取供以后使用。
例如,相匹配lady_killer9中的lady_killer但是不想匹配lasy_killers中的lady_killer,可以写成lady_killer(?=9)
(?!pattern) 非获取匹配,正向否定预查,匹配后面不是pattern的数据,该匹配不需要获取供以后使用。
例如,有如下需求需要匹配
小写字母、数字组合,不能纯数字或者纯字母,6-16个字符。
请读者自行实验~
(?<=pattern) 非获取匹配,反向肯定预查,与正向肯定预查类似,只是方向相反,即匹配前面是pattern的数据。
例如,匹配前面是lady_killer的9
(?<!pattern) 非获取匹配,反向否定预查,与正向否定预查类似,只是方向相反,即匹配前面不pattern的数据。
例如,有如下需求需要匹配
小写字母、数字组合,可以有下划线,但不能以下划线开头
请读者自行实验~
正则分组
分组内部引用 \n
当你要匹配单引号或双引号包裹的数据时,你可能这样写
['"].*['"]
但是结果却是不对的,因为可能出现这种情况
那我们怎么知道前面匹配了什么呢?这是可以在正则中分组并在后面引用
(['"]).*\1
代码
def test_group_ref():
pattern = r"""(['"]).*\1"""
str1 = "'hi'"
str2 = "'hi\""
res1 = re.match(pattern,str1)
if res1:
print("找到了str1")
res2 = re.match(pattern,str2)
if res2:
print("找到了str2")
分组获取与命名 ?P
.group(index)获取分组结果,0是整个数据
在分组()内的前面写上?P<group_name>即可命名,正则新加分组时,不用索引的代码就不用动了,.group(group_name)获取name分组结果
代码:
def test_group_name():
pattern = "https://([a-z.]+)/([a-z\d_.]+)/article/details/(\d+)"
blog1 = "https://blog.csdn.net/lady_killer9/article/details/107630277"
blog2 = "https://blog.csdn.net/lady_killer9/article/details/xxxx"
res1 = re.match(pattern,blog1)
res2 = re.match(pattern,blog2)
if res1:
print("res1:")
print(res1.group(0))
print(res1.group(1))
print(res1.group(2))
print(res1.group(3))
if res2:
print("res2:")
print(res1.group(0))
print(res1.group(1))
print(res1.group(2))
print(res1.group(3))
pattern_name = "https://(?P<domain>[a-z.]+)/(?P<blogger>[a-z\d_.]+)/article/details/(\d+)"
res3 = re.match(pattern_name, blog1)
if res3:
print("res3:")
print(res3.group(0))
print(res3.group(1))
print(res3.group('blogger'))
print(res3.group(2))
print(res3.group(3))
全部代码:
import re
def test_group_ref():
pattern = r"""(['"]).*\1"""
str1 = "'hi'"
str2 = "'hi\""
res1 = re.match(pattern,str1)
if res1:
print("找到了str1")
res2 = re.match(pattern,str2)
if res2:
print("找到了str2")
def test_group_name():
pattern = "https://([a-z.]+)/([a-z\d_.]+)/article/details/(\d+)"
blog1 = "https://blog.csdn.net/lady_killer9/article/details/107630277"
blog2 = "https://blog.csdn.net/lady_killer9/article/details/xxxx"
res1 = re.match(pattern,blog1)
res2 = re.match(pattern,blog2)
if res1:
print("res1:")
print(res1.group(0))
print(res1.group(1))
print(res1.group(2))
print(res1.group(3))
if res2:
print("res2:")
print(res1.group(0))
print(res1.group(1))
print(res1.group(2))
print(res1.group(3))
pattern_name = "https://(?P<domain>[a-z.]+)/(?P<blogger>[a-z\d_.]+)/article/details/(\d+)"
res3 = re.match(pattern_name, blog1)
if res3:
print("res3:")
print(res3.group(0))
print(res3.group(1))
print(res3.group('blogger'))
print(res3.group(2))
print(res3.group(3))
if __name__ == '__main__':
# test_group_ref()
test_group_name()
运行截图:
参考
b站张大仙20200810投稿所有视频弹幕
python3.7官方文档:re---正则表达式操作
《python核心编程》
更多python相关内容:【python总结】python学习框架梳理
本人b站账号:lady_killer9
有问题请下方评论,转载请注明出处,并附有原文链接,谢谢!如有侵权,请及时联系。