1、效果
2、源代码
已经把注释写的很清楚了
#! -*- coding: utf-8 -*-
"""
Author: ZhenYuSha
Create type_time: 2020-4-7
Info: 正则模块
-------------------- 1.元字符 --------------------
-----正则元字符------描述--------------------------------
. 匹配任意字符(不包括换行符)
^ 匹配开始位置,多行模式下匹配每一行的开始
$ 匹配结束位置,多行模式下匹配每一行的结束
* 匹配前一个元字符0到多次
+ 匹配前一个元字符1到多次
? 匹配前一个元字符0到1次
{m,n} 匹配前一个元字符m到n次
\\ 转义字符,跟在其后的字符将失去作为特殊元字符的含义,例如\\.只能匹配.,不能再匹配任意字符
[] 字符集,一个字符的集合,可匹配其中任意一个字符
| 逻辑表达式 或 ,比如 a|b 代表可匹配 a 或者 b
(...) 分组,默认为捕获,即被分组的内容可以被单独取出,默认每个分组有个索引,从 1 开始,按照"("的顺序决定索引值
(?iLmsux) 分组中可以设置模式,iLmsux之中的每个字符代表一个模式,用法参见 模式 I
(?:...) 分组的不捕获模式,计算索引时会跳过这个分组
(?P<name>...) 分组的命名模式,取此分组中的内容时可以使用索引也可以使用name
(?P=name) 分组的引用模式,可在同一个正则表达式用引用前面命名过的正则
(?#...) 注释,不影响正则表达式其它部分,用法参见 模式 I
(?=...) 顺序肯定环视,表示所在位置右侧能够匹配括号内正则
(?!...) 顺序否定环视,表示所在位置右侧不能匹配括号内正则
(?<=...) 逆序肯定环视,表示所在位置左侧能够匹配括号内正则
(?<!...) 逆序否定环视,表示所在位置左侧不能匹配括号内正则
(?(id/name)yes|no) 若前面指定id或name的分区匹配成功则执行yes处的正则,否则执行no处的正则
\number 匹配和前面索引为number的分组捕获到的内容一样的字符串
\A 匹配字符串开始位置,忽略多行模式
\Z 匹配字符串结束位置,忽略多行模式
\b 匹配位于单词开始或结束位置的空字符串
\B 匹配不位于单词开始或结束位置的空字符串
\d 匹配一个数字, 相当于 [0-9]
\D 匹配非数字,相当于 [^0-9]
\s 匹配任意空白字符, 相当于 [ \t\n\r\f\v]
\S 匹配非空白字符,相当于 [^ \t\n\r\f\v]
\w 匹配数字、字母、下划线中任意一个字符, 相当于 [a-zA-Z0-9_]
\W 匹配非数字、字母、下划线中的任意字符,相当于 [^a-zA-Z0-9_]
-----正则元字符------描述--------------------------------
-------------------- 2.模式 ----------------------
re.compile("规则", re.模式)
re.I 忽略大小写
re.L 字符集本地化,表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
re.M 多行模式 改变 ^ 和 $ 的行为
re.S 即为 . 并且包括换行符在内的任意字符
re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
re.X 为了增加可读性,忽略空格和 # 后面的注释
-------------------- 2.模式 ----------------------
-------------------- 3.函数 ----------------------
* 为比较常用的
* compile(pattern, flags=0)
给定一个正则表达式 pattern,指定使用的模式 flags 默认不使用任何模式, 返回一个 SRE_Pattern(参见 4.re 内置对象用法) 对象
* findall(pattern, string, flags=0)
参数 pattern 为正则表达式, string 为待操作字符串, flags 为所用模式,函数作用为在待操作字符串中寻找所有匹配正则表达式的字串,返回一个列表,如果没有匹配到任何子串,返回一个空列表。
* match(pattern, string, flags=0)
使用指定正则去待操作字符串中寻找可以匹配的子串, 返回匹配上的第一个字串,并且不再继续找,需要注意的是 match 函数是从字符串开始处开始查找的,如果开始处不匹配,则不再继续寻找,返回值为 一个 SRE_Match (参见 4.re 内置对象用法) 对象,找不到时返回 None
* sub(pattern, repl, string, count=0, flags=0)
替换函数,将正则表达式 pattern 匹配到的字符串替换为 repl 指定的字符串, 参数 count 用于指定最大替换次数
* split(pattern, string, maxsplit=0, flags=0)
maxsplit 指定切分次数, 函数使用给定正则表达式寻找切分字符串位置,返回包含切分后子串的列表,如果匹配不到,则返回包含原字符串的一个列表
* search(pattern, string, flags=0)
函数类似于 match,不同之处在于不限制正则表达式的开始匹配位置
finditer(pattern, string, flags=0)
参数和作用与 findall 一样,不同之处在于 findall 返回一个列表, finditer 返回一个迭代器, 而且迭代器每次返回的值并不是字符串,而是一个 SRE_Match (参见 4. re 内置对象用法) 对象,这个对象的具体用法见 match 函数
escape(pattern)
转义 如果你需要操作的文本中含有正则的元字符,你在写正则的时候需要将元字符加上反斜扛 \ 去匹配自身, 而当这样的字符很多时,写出来的正则表达式就看起来很乱而且写起来也挺麻烦的,这个时候你可以使用这个函数
template(pattern, flags=0)
和 compile 差不多,但不支持 +、?、*、{} 等这样的元字符,只要是需要有重复功能的元字符,就不支持
subn(pattern, repl, string, count=0, flags=0)
作用与函数 sub 一样, 唯一不同之处在于返回值为一个元组,第一个值为替换后的字符串,第二个值为发生替换的次数
purge()
当你在程序中使用 re 模块,无论是先使用 compile 还是直接使用比如 findall 来使用正则表达式操作文本,re 模块都会将正则表达式先编译一下,
并且会将编译过后的正则表达式放到缓存中,这样下次使用同样的正则表达式的时候就不需要再次编译, 因为编译其实是很费时的,这样可以提升效率,而默认缓存的正则表达式的个数是 100, 当你需要频繁使用少量正则表达式的时候,缓存可以提升效率,而使用的正则表达式过多时,缓存带来的优势就不明显了
fullmatch(pattern, string, flags=0)
如果整个字符串与正则表达式模式匹配,则返回相应的匹配对象。 如果字符串与模式不匹配,则返回None; 请注意,这与零长度匹配不同。
-------------------- 3.函数 ----------------------
---------------- 4.re 内置对象用法 ---------------
SRE_Pattern 这个对象是一个编译后的正则表达式,编译后不仅能够复用和提升效率,同时也能够获得一些其他的关于正则表达式的信息
属性:
flags 编译时指定的模式
groupindex 以正则表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。
groups 正则表达式中分组的数量
pattern 编译时用的正则表达式
SRE_Match 这个对象会保存本次匹配的结果,包含很多关于匹配过程以及匹配结果的信息
属性:
endpos 本次搜索结束位置索引
lastgroup 本次搜索匹配到的最后一个分组的别名
lastindex 本次搜索匹配到的最后一个分组的索引
pos 本次搜索开始位置索引
re 本次搜索使用的 SRE_Pattern 对象
regs 列表,元素为元组,包含本次搜索匹配到的所有分组的起止位置
string 本次搜索操作的字符串
函数:
end([group=0]) 返回指定分组的结束位置,默认返回正则表达式所匹配到的最后一个字符的索引
expand(template) 根据模版返回相应的字符串,类似与 sub 函数里面的 repl, 可使用 \1 或者 \g<name> 来选择分组
group([group1, ...]) 根据提供的索引或名字返回响应分组的内容,默认返回 start() 到 end() 之间的字符串, 提供多个参数将返回一个元组
groupdict([default=None]) 返回 返回一个包含所有匹配到的命名分组的字典,没有命名的分组不包含在内,key 为组名,value 为匹配到的内容,参数 default 为没有参与本次匹配的命名分组提供默认值
groups([default=None]) 以元组形式返回每一个分组匹配到的字符串,包括没有参与匹配的分组,其值为 default
span([group]) 返回指定分组的起止位置组成的元组,默认返回由 start() 和 end() 组成的元组
start([group]) 返回指定分组的开始位置,默认返回正则表达式所匹配到的第一个字符的索引
---------------- 4.re 内置对象用法 ---------------
-------------------- 5.分组用法 ------------------
5.1 正则表达式中用小括号 "(" 表示分组,按照每个分组中前半部分出现的顺序 "(" 判定分组的索引,索引从 1 开始,每个分组在访问的时候可以使用索引,也可以使用别名
s = 'Hello, Mr.Gumby : 2016/10/26'
p = re.compile("(?P<name>\w+\.\w+).*?(\d+)(?#comment)")
m = p.search(s)
# 使用别名访问
print m.group('name')
# output> Mr.Gumby
# 使用分组访问
print m.group(2)
# output> 2016
5.2 也可能只是为了把正则表达式分组,而不需要捕获其中的内容,这时候可以使用非捕获分组
5.3 如果你在写正则的时候需要在正则里面重复书写某个表达式,那么你可以使用正则的引用分组功能,需要注意的是引用的不是前面分组的 正则表达式 而是捕获到的 内容,并且引用的分组不算在分组总数中
-------------------- 5.分组用法 ------------------
-------------------- 6.环视用法 ------------------
环视还有其他的名字,例如 界定、断言、预搜索等,叫法不一。
环视是一种特殊的正则语法,它匹配的不是字符串,而是 位置,其实就是使用正则来说明这个位置的左右应该是什么或者应该不是什么,然后去寻找这个位置。
环视的语法有四种,具体如下:
s = 'Hello, Mr.Gumby : 2016/10/26 Hello,r.Gumby : 2016/10/26'
# 不加环视限定
print re.compile("(?P<name>\w+\.\w+)").findall(s)
# output> ['Mr.Gumby', 'r.Gumby']
# 环视表达式所在位置 左边为 "Hello, "
print re.compile("(?<=Hello, )(?P<name>\w+\.\w+)").findall(s)
# output> ['Mr.Gumby']
# 环视表达式所在位置 左边不为 ","
print re.compile("(?<!,)(?P<name>\w+\.\w+)").findall(s)
# output> ['Mr.Gumby']
# 环视表达式所在位置 右边为 "M"
print re.compile("(?=M)(?P<name>\w+\.\w+)").findall(s)
# output> ['Mr.Gumby']
# 环视表达式所在位置 右边不为 r
print re.compile("(?!r)(?P<name>\w+\.\w+)").findall(s)
# output> ['Mr.Gumby']
-------------------- 6.环视用法 ------------------
"""
import re
def s_print(query, max_number=15):
"""格式打印"""
def is_chinese(word):
"""判断是否含中文"""
for ch in word:
if '\u4e00' <= ch <= '\u9fff':
return True
return False
def rule_print(word, chinese, fill=" "):
"""规则打印"""
if chinese:
return word + 2*(max_number - len(word))*fill
else:
return word + (max_number - len(word))*fill
return rule_print(query, is_chinese(query))
# return query.ljust(max_number+len(query), "*") # 中文有问题
# return "{:<{len}}\t".format(query, len=max_number - len(query.encode("GBK")) + len(query))
def find_it(re_rule, context):
"""查找结果"""
re_arr = re.findall(re_rule, context)
print("用户: %s 结果: %s" % (s_print(context), "不匹配" if re_arr == list() else "匹配"))
def print_result(re_rule, re_comp, string_list):
"""打印结果"""
print("------------------------------------------------------")
print("规则:", re_rule)
print("------------------------------------------------------")
for tmp in string_list:
find_it(re_comp, tmp)
if __name__ == '__main__':
str_list = ["我不知道为什么你可以进来?", "你认识她嘛?", "你知道嘛?", "不知道", "你知道不?"]
# 不包含"不",且包含"知道"(顺序的,"知道"后面的"不"不处理)
ru_1 = "[^不]+知道.*"
# 不包含("不"或者"否"),且包含"知道"(无顺序的)
ru_2 = "^(?!.*?(不|否))(?=.*?知道{1,}).+$"
re_1 = re.compile(ru_1)
re_2 = re.compile(ru_2)
print_result(ru_1, re_1, str_list)
print_result(ru_2, re_2, str_list)