1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
| import re
""" :author 易果啥笔 :apiNote re模块主要定义了9个常量、12个函数 :data 2022.01.18
"""
def regex_flags(flag): if flag == 'IGNORECASE': ''' 语法: re.IGNORECASE 作用: 进行忽略大小写匹配。 ''' text = '易果啥笔a' pattern = r'易果啥笔A' print("默认模式:", re.findall(pattern, text)) print("忽略大小写模式:", re.findall(pattern, text, re.IGNORECASE))
if flag == 'ASCII': ''' 语法: re.ASCII 作用: 顾名思义,ASCII表示ASCII码, 让 \w, \W, \b, \B, \d, \D, \s 和 \S 只匹配ASCII, 而不是Unicode。 在默认匹配模式下\w+匹配到了下面例子的所有字符串, 而在ASCII模式下,只匹配到了a、b、c(ASCII编码支持的字符)。 注意:这只对字符串匹配模式有效,对字节匹配模式无效。 ''' text = 'a易果啥笔b易果啥笔c' pattern = r'\w+' print("默认模式Unicode:", re.findall(pattern, text)) print("ASCII模式:", re.findall(pattern, text, re.ASCII))
if flag == 'DOTALL': ''' 语法: re.DOTALL 作用: DOT表示.,ALL表示所有,连起来就是 .匹配所有, 包括换行符\n。默认模式下.是不能匹配换行符\n的。 ''' text = 'a易果啥笔\n易果啥笔c' pattern = r'.*' print(text) print("默认模式:", re.findall(pattern, text)) print("DOTALL模式:", re.findall(pattern, text, re.DOTALL))
if flag == 'MULTILINE': ''' 语法: re.MULTILINE 作用: 多行模式,当某字符串中有换行符\n,默认模式下是不支持换行符特性的, 比如:行开头 和 行结尾,而多行模式下是支持匹配行开头的。 下面的例子中,正则表达式中^表示匹配行的开头, 默认模式下它只能匹配字符串的开头;而在多行模式下,它还可以匹配换行符\n后面的字符。 注意:正则语法中^匹配行开头、\A匹配字符串开头, 单行模式下它两效果一致,多行模式下\A不能识别\n。 ''' text = '易果啥笔\n易果啥笔' pattern = r'^易果啥笔' print(text) print("默认模式:", re.findall(pattern, text)) print("MULTILINE模式:", re.findall(pattern, text, re.MULTILINE))
if flag == 'VERBOSE': ''' 语法: re.VERBOSE 作用: 详细模式,简单来说,在正则表达式中可以加注释 默认模式下并不能识别正则表达式中的注释,而详细模式是可以识别的。 当一个正则表达式十分复杂的时候,详细模式能为你提供另一种注释方式, ''' text = '易果啥笔' pattern = r''' ^易果 # 量词 啥笔 # 名词 ''' print(text) print("默认模式:", re.findall(pattern, text)) print("MULTILINE模式:", re.findall(pattern, text, re.VERBOSE))
if flag == 'LOCALE': ''' 语法: re.LOCALE 作用: 由当前语言区域决定 \w, \W, \b, \B 和大小写敏感匹配, 这个标记只能对byte样式有效。官方已经不推荐使用, ''' if flag == 'UNICODE': ''' 语法: re.UNICODE 作用: 与 ASCII 模式类似,匹配unicode编码支持的字符, 但是 Python 3 默认字符串已经是Unicode,所以有点冗余。 ''' if flag == 'DEBUG': ''' 语法: re.DEBUG 作用: 显示编译时的debug信息,目前这个debug信息笔者不太清楚 ''' text = '异国傻逼a' pattern = r'异国傻逼A' print("DEBUG模式:", re.findall(pattern, text, re.DEBUG | re.IGNORECASE))
if flag == 'TEMPLATE': ''' 语法: re.TEMPLATE 作用: 没搞懂TEMPLATE的具体用处, 源码注释中写着:disable backtracking(禁用回溯) ''' ''' 常量总结: 1. 9个常量中,前5个(IGNORECASE、ASCII、DOTALL、MULTILINE、VERBOSE)有用处, 两个(LOCALE、UNICODE)官方不建议使用、 两个(TEMPLATE、DEBUG)试验性功能,不能依赖。 2. 常量在re模块的常用函数中都可以使用,查看源码可得知。 3. 常量可叠加使用,因为常量值都是2的幂次方值, 所以是可以叠加使用的,叠加时请使用 | 符号,请勿使用 + 符号 '''
def regex_function(funcition_name): """ re模块有12个函数 """
""" 1.查找一个匹配项 查找并返回一个匹配项的函数有3个:search、match、fullmatch, 他们的区别分别是: search: 查找任意位置的一个匹配项 match: 必须从字符串开头匹配 fullmatch: 整个字符串与正则完全匹配 查找一个匹配项 返回的都是一个匹配对象(Match),其含有的方法有: 1. group(index) 某个组匹配的结果(无匹配时调用会报错) 2. groups() 所有分组的匹配结果,每个分组组成的结果以列表返回(无匹配时调用会报错) 3. groupdict() 返回组名作为key,每个分组的匹配结果作为value的字典 4. span([group]) 获取组的开始和结束位置 5. expand(template) 使用组的匹配结果来替换template中的内容,并把替换后的字符串返回 """
if funcition_name == 'one_match': text = 'I have 9 students.' pattern = r'(?P<one>\w+) (?P<two>\w+) (?P<three>\d+) (?P<four>\w+)' print("search:", re.search(pattern, text).group(0)) print("search:", re.search(pattern, text).groups()) print("search:", re.search(pattern, text).group(1)) print("search:", re.search(pattern, text).group(2)) print("search:", re.search(pattern, text).group(3)) print("search:", re.search(pattern, text).groupdict()['one'])
if funcition_name == 'many_match': """ 2.查找多个匹配项 查找多项函数主要有:findall函数 与 finditer函数: 1. findall: 从字符串任意位置查找,返回一个列表 2. finditer:从字符串任意位置查找,返回一个迭代器 两个方法基本类似, 只不过一个是返回列表,一个是返回迭代器。 列表是一次性生成在内存中,而迭代器是需要使用时一点一点生成出来的,内存使用更优。 如果可能存在大量的匹配项的话,建议使用finditer函数,一般情况使用findall函数基本没啥影响。 """ text = '我的电话号码是:17377762736,我的妹妹的电话号码是:18976562836,我们都住在3601寝室,我的帐号是11290378914。' pattern = r'(?P<phone>1[2-9][1-9]{9})' print(re.findall(pattern, text)) match_list = list(re.finditer(pattern, text))
if funcition_name == 'split': """ 3.分割 re.split(pattern, string, maxsplit=0, flags=0) 函数: 用 pattern 分开 string , maxsplit表示最多进行分割次数,值为0表示不限分割次数 flags表示模式,就是上面的常量! """ text = 'Haha,Heihei,Hehe.哈哈' pattern = r'[,,.]' print("正则表达式进行分割:", re.split(pattern, text, maxsplit=0, flags=0))
""" 注意:str模块也有一个 split函数 ,那这两个函数该怎么选呢? str.split函数功能简单,不支持正则分割,而re.split支持正则。 在 不需要正则支持 且 数据量和数次不多 的情况下使用str.split函数更合适, 反之则使用re.split函数。 """
if funcition_name == 'replace': """ 4.替换 替换主要有sub函数 与 subn函数,他们功能类似 sub函数的用法: re.sub(pattern, repl, string, count=0, flags=0) 函数参数讲解:repl替换掉string中被pattern匹配的字符, count表示最大替换次数,flags表示正则表达式的常量。 """ text = 'Haha,Heihei,Hehe.哈哈' pattern = r'[,,.]' print("sub函数替换:", re.sub(pattern, '...', text, count=0, flags=0))
''' re.subn(pattern, repl, string, count=0, flags=0) 返回一个元组,第一个元素即为sub()的返回值,第二个元素表示匹配成功的次数。 ''' print("subn函数替换:", re.subn(pattern, '...', text, count=0, flags=0))
""" 如果想要对替换的所有字符串中的某个字符串单独替换成其他字符串,可以传入repl的函数形式: """ matchobj = lambda matchobj: '......' if matchobj.group(0) != ',' else '。' print("函数替换:", re.sub(pattern, matchobj, text, flags=re.IGNORECASE))
def pattern_obj(): """ 前面我们一直使用的是re.啥啥啥,这个re我们也可以自定义,这就是Pattern对象,即正则对象Pattern。 """ text = '我的电话号码是:17377777777,我的妹妹的电话号码是:18977777777,我们都住在3601寝室,我的帐号是11111111111。' pattern = r'(?P<phone>1[2-9][0-9]{9})' pattern_obj = re.compile(pattern) match_result1 = pattern_obj.findall(text) print(match_result1)
""" 既然有re就够了,为什么还要有pattern对象呢? 官方文档推荐:在多次使用 "一个正则表达式" 时推荐使用正则对象Pattern以增加复用性, 因为通过 re.compile(pattern) 编译后的模块级函数会被缓存。。。 比如前面的pattern_obj这个pattern对象,用于从一串文本中找出电话号码,我们可以反复使用这个对象: """ text2 = '我爸爸的电话号码是11011011101,我姐姐的电话号码是12345678910,呀呀呀' match_result2 = pattern_obj.findall(text2) print(match_result2)
""" 常量也可以简写,具体参考下面的re模块源码:
class RegexFlag(enum.IntFlag): ASCII = A = sre_compile.SRE_FLAG_ASCII # assume ascii "locale" IGNORECASE = I = sre_compile.SRE_FLAG_IGNORECASE # ignore case LOCALE = L = sre_compile.SRE_FLAG_LOCALE # assume current 8-bit locale UNICODE = U = sre_compile.SRE_FLAG_UNICODE # assume unicode "locale" MULTILINE = M = sre_compile.SRE_FLAG_MULTILINE # make anchors look for newline DOTALL = S = sre_compile.SRE_FLAG_DOTALL # make dot match newline VERBOSE = X = sre_compile.SRE_FLAG_VERBOSE # ignore whitespace and comments # sre extensions (experimental, don't rely on these) TEMPLATE = T = sre_compile.SRE_FLAG_TEMPLATE # disable backtracking DEBUG = sre_compile.SRE_FLAG_DEBUG # dump pattern after compilation
"""
if __name__ == '__main__': """ 注意:Python中字符串前面加上r表示原生字符串,试比较下面两行: """
|