python 常用模块 之 re

一、什么是正则表达式?
    是一种字符串匹配的模式(pattern),更像是一种逻辑公式。
    简单来说就是python中必备的一种工具,主要是用来查找和匹配字符串的。
    正则表达式在爬虫方面用的多。
    1、就是通过普通字符+特殊字符组成一个字符串,然后按照特定的语法描述
    一个规则,通过这个规则来查询过滤对应的字符串。
    2、正则表达式的使用非常的广泛,是一门独立的语言,基本各个领域都有所使用
    ,如果在python代码中使用正则,需要借助于内置模块re
    作用与意义: 找出规律、描述规律、提取数据。
二、python匹配字符及说明 
rrrrrrrrr 正则表达式前面的公式最好前置r,‘r’ 前缀
特殊符号有以下----
^  匹配字符串开头
    例:print(re.findall('^sb', 'sb is wangbadan'))
$  匹配字符串的末尾
    例:print(re.findall('sb$', 'wangbadan is dsb'))
.  匹配任意字符,除了换行符,当re.DOTALL re.S被指定时,则可匹配包括换行符的的任意字符
    例:print(re.findall('s.b', 'sb s11b sab s?b'))  # ['sab', 's?b']    
    例:print(re.findall('s..b', 'sb s11b sab s?b'))  # ['s11b']    
    例:print(re.findall('s.{1,3}b', 'sb s11b sa11b s?b'))  # ['s11b']
反斜杠“\”
    反斜杠在正则表达式里面不能单独使用,甚至在整个Python里都不能单独使用。
    反斜杠需要和其他的字符配合使用来把特殊符号变成普通符号,把普通符号变成特殊符号。如:“\n”。
[...] 用来表示一组字符,单独列出:[amk] 表示匹配 ’a‘、'm'、'k'
    例:print(re.findall('s[a-z A-Z0-9]b', 'sab s*b s8b sAb!'))  # ['sab', 's8b', 'sAb']
    例:print(re.findall('s[-0-9]b', 's-b s*b s8b sAb!'))  # ['s-b', 's8b']  -要在最前面
    例:print(re.findall('s[\n0-9]b', 's\nb s*b s8b sAb!',re.S))  # ['s\nb', 's8b']    
[^...] 不在[]中的字符,单独列出:[^amk] 表示匹配 不包含’a‘、'm'、'k'
    例:print(re.findall('s[^\n0-9]b', 's\nb s*b s8b sAb!',re.S))  # ['s*b', 'sAb']              

量词组有以下----
*  匹配0-n个表达式  贪婪
+  匹配1-n个表达式  贪婪
?  匹配0-1个表达式 非贪婪方式
{n} 精准匹配n个前面表达式
{n,m} 匹配n-m次由前面的正则表达式定义的片段, 贪婪方式     
a|b  匹配a 或者b
    例:print(re.findall('s.b|s..b', 'sab, saab sbsbbbb saaab'))  # ['sab', 'saab', 'sbsb']
(re) 匹配括号内的表达式,也表示一个组

字母代号有以下----
\w 匹配任意字母和数字
    例:print(re.findall(r'\w{3}', '123 b456 67a')) # ['123', 'b45', '67a']
\W 匹配任意非字母数字 \w的取反
    例:print(re.findall(r'\W{3}', '123=¥% b456 67a')) # ['=¥%']
\s 匹配任意空白字符 ,可以设置数量,等价于\t \n \r \f
    例:print(re.findall('\s', 'abc= ?1  2'))  # [' ', ' ', ' ']
    例:print(re.findall('\s{1,2}', 'abc= ?1  2'))  # [' ', '  ']
\S 匹配任意非空字符
    例:print(re.findall('\S', 'abc= ?1  2'))  # ['a', 'b', 'c', '=', '?', '1', '2']
    例:print(re.findall('\S{3,3}', 'abc= ?1  2'))  # ['abc']  长度是3的非空字符
\d 匹配任意数字  等价于0-9
    例:print(re.findall(r'变压器\d', '变压器1222 v变压器b mast 变压器'))  # ['变压器1']
    例:print(re.findall(r'变压器\d*', '变压器1222 v变压器b mast 变压器'))  # ['变压器1222', '变压器', '变压器']
    例:print(re.findall(r'变压器\d{0,5}', '变压器1222 v变压器b mast 变压器'))  # ['变压器1222', '变压器', '变压器']
    例:print(re.findall(r'变压器\d?', '变压器1222 v变压器b mast 变压器'))  # []
    例:print(re.findall(r'变压器\d+', '变压器1222 v变压器b mast 变压器'))  # ['变压器1222']
    例:print(re.findall(r'\d{3}', '123 b456 67a')) # ['123', '456']
\D  匹配任意非数字  \d的取反
    例:print(re.findall('\D', 'aA_d\n-s\t( \\)*)3'))  # ['a', 'A', '_', 'd', '\n', '-', 's', '\t', '(', ' ', '\\', ')', '*', ')']
    例:print(re.findall('\D', 'abc=?123'))  # ['a', 'b', 'c', '=', '?']
\A  匹配字符串开始 只找开头的
    例:print(re.findall('\Aalex', 'alex is sbalex'))  # ['alex']
    例:print(re.findall('\Aalex', ' alex is sbalex'))  # [] 开头有空格
    例:print(re.findall('alex', ' alex is sbalex'))  # ['alex', 'alex']
\Z  匹配字符串结尾。
    例:print(re.findall('sb\Z', 'alex is sb'))  # ['sb']
\b  匹配一个单词边界,也就是指单词和空格间的位置,例如,'er\b'可以匹配’never‘中的er,但不能匹配’verb‘中的er
    例:print(re.findall(r'er\b', 'nver verb master'))  # ['er', 'er'],其实就是在单词屁股后面的。
\B  匹配非单词边界,也就是屁股前面的,不算单词屁股。例如:’er\B‘可以匹配’verb‘中的er,但不能匹配’never‘中的er
    例:print(re.findall(r'er\B', 'nver verb master'))  # ['er']   


三、re模块常量
    常量即表示不可更改的变量,一般用于做标记。
    re模块中有9个常量,常量的值都是int类型!
    最常用的也就4个 I忽略大小写 A ascii S 全部字符 M  多线
  1. IGNORECASE
    语法: re.IGNORECASE 或简写为 re.I
    作用: 进行忽略大小写匹配
  2. ASCII
    语法: re.ASCII 或简写为 re.A
    作用: 顾名思义,ASCII表示ASCII码的意思,让 \w, \W, \b, \B, \d,
     \D, \s 和 \S 只匹配ASCII,而不是Unicode。
  3. DOTALL
    语法: re.DOTALL 或简写为 re.S
    作用: DOT表示.,ALL表示所有,连起来就是.匹配所有,包括换行符\n。
    默认模式下.是不能匹配行符\n的。
    默认匹配模式下.并不会匹配换行符\n。
  4. MULTILINE
    语法: re.MULTILINE 或简写为 re.M
    作用: 多行模式,当某字符串中有换行符\n,默认模式下是不支持换行符特性的
    ,比如:行开头 和 行结尾,而多行模式下是支持匹配行开头的。
    正则表达式中^表示匹配行的开头,默认模式下它只能匹配字符串的开头;
    而在多行模式下,它还可以匹配 换行符\n后面的字符。
    注意:正则语法中^匹配行开头、\A匹配字符串开头,单行模式下它两效果
    一致,多行模式下\A不能识别\n。
  5. VERBOSE
    语法: re.VERBOSE 或简写为 re.X
    作用: 详细模式,可以在正则表达式中加注解!
    默认模式下并不能识别正则表达式中的注释,而详细模式是可以识别的。
    当一个正则表达式十分复杂的时候,详细模式或许能为你提供另一种注释方式,
    但它不应该成为炫技的手段,建议谨慎考虑后使用!
  6.LOCALE
    语法: re.LOCALE 或简写为 re.L
    作用: 由当前语言区域决定 \w, \W, \b, \B 和大小写敏感匹配,这个标记
    只能对byte样式有效。这个标记官方已经不推荐使用,因为语言区域机制很不可靠,
    它一次只能处理一个 "习惯”,而且只对8位字节有效。
    注意: 由于这个标记官方已经不推荐使用
  7.UNICODE
    语法: re.UNICODE 或简写为 re.U
    作用: 与 ASCII 模式类似,匹配unicode编码支持的字符,但是 Python 3 
    默认字符串已经是Unicode,所以有点冗余。
  8. DEBUG
    语法: re.DEBUG
    作用: 显示编译时的debug信息。
  9.TEMPLATE
    语法: re.TEMPLATE 或简写为 re.T
    作用: disable backtracking(禁用回溯)
  10. 常量总结
    9个常量中,前5个(IGNORECASE、ASCII、DOTALL、MULTILINE、VERBOSE)有用处,
    两个(LOCALE、UNICODE)官方不建议使用、
    两个(TEMPLATE、DEBUG)试验性功能,不能依赖。
    常量在re常用函数中都可以使用,查看源码可得知。
    常量可叠加使用,因为常量值都是2的幂次方值,所以是可以叠加使用的,叠加时
    请使用 | 符号,请勿使用+ 符号!
    re.S | re.M   # 全部匹配 and 多行模式

四、re模块共12个函数、用法

#  re.search()   re.match()  re.fullmatch()都是查找单项
3.1 re.search(pattern= , string, flags)  # 匹配连续的多个数值
    #查找任意位置 即使有多个匹配项,但search函数值返回一个。
    例:print(('search:', re.search('sb', 'wangbadan is sb').group()))  # ('search:', 'sb')
3.2 re.match(pattern=, string, flags)  # 从首字母开始开始匹配,string如果包含pattern子串,则匹配成功,返回Match对象,失败则返回None,若要完全匹配,pattern要以$结尾。
    #从字符串开头开始匹配 开关没有就是没有
    例:print("match:", re.match("sb", 'wangbadan is dsb '))  # match: None
    例:print("match:", re.match("sb", 'sbwangbadan is dsb ').group())  # match: sb
3.3 re.fullmatch(pattern= , string, flags)
    #整个字符串完全匹配 pattern必须与string完全相同
    例:print('fullmatch:',re.fullmatch('dsb', 'wangbadan is dsb'))  # fullmatch: None
    例:print('fullmatch:',re.fullmatch('dsb', 'dsb').group())  # fullmatch: dsb   

# re.findall() re.finditer()都是返回多项
3.4 re.findall(pattern=, string, flags)
    例:print("findall:", re.findall("dsb", 'dsbasdfdsb,sdfdsb..!'))  # findall: ['dsb', 'dsb', 'dsb']
3.5 re.finditer(pattern=, string, flags)
    例:print("finditer:", list(re.finditer("dsb", 'dsbasdfdsb,sdfdsb..!')))  # finditer: [<re.Match object; span=(0, 3), match='dsb'>, <re.Match object; span=(7, 10), match='dsb'>, <re.Match object; span=(14, 17), match='dsb'>]
    如果可能存在大量的匹配项的话,建议使用finditer函数,一般情况使用findall函数基本没啥影响。

# 分割
3.6 re.split(pattern=, string,maxsplit= flags)
  函数:用 pattern 分开 string , maxsplit表示最多进行分割次数, flags表示模式
    text = '变压器招标采购,500kw变压器,招标文件'
    pattern = r',|,'
    print('split:', re.split(pattern, text, maxsplit=5, flags=re.I))  # split: ['变压器招标采购', '500kw变压器', '招标文件']
  str.split功能简单,不支持正则分割,而re.split支持正则。
  速度上:str.split适合小数据,re.split适合大数据与爬虫

# 替换    替换主要有sub函数 与 subn函数,他们功能类似!
3.7 re.sub(pattern= , repl,string, count, flags)
   #函数参数讲解:repl替换掉string中被pattern匹配的字符, count表示
     最大替换次数,flags表示正则表达式的常量。
     repl替换内容既可以是字符串,也可以是一个函数
   #例: repl为字符串
    text = '变压器招标采购,500kw变压器,招标文件变压器'
    pattern = r','   # 查找分割符为,
    repl = "、"   # 替换分割符为字符串
    print('sub-repl:', re.sub(pattern, repl, text, count=5, flags=re.I))  # sub-repl: 变压器招标采购、500kw变压器、招标文件变压器

    #例: repl为函数
    text = '变压器招标采购,500kw变压器,招标文件变压器'
    pattern = r','   # 查找分割符为,
    repl = lambda matchobj:' ' if matchobj !=',' else ':'   # 替换分割符为函数
    print('sub-repl:', re.sub(pattern, repl, text, count=5, flags=re.I))  # sub-repl: 变压器招标采购 500kw变压器 招标文件变压器

3.8 re.subn(pattern= , repl,string, count, flags)
   #re.subn(pattern, repl, string, count=0, flags=0) 函数
     与 re.sub函数 功能一致,只不过返回一个元组 (字符串, 替换次数)。
    #例: repl为字符串
    text = '变压器招标采购,500kw变压器,招标文件变压器'
    pattern = r','   # 查找分割符为,
    repl = "、"   # 替换分割符为字符串
    print('subn-repl:', re.subn(pattern, repl, text, count=5, flags=re.I))  # subn-repl: ('变压器招标采购、500kw变压器、招标文件变压器', 2)

    #例: repl为函数
    text = '变压器招标采购,500kw变压器,招标文件变压器'
    pattern = r','   # 查找分割符为,
    repl = lambda matchobj:' ' if matchobj !=',' else ':'   # 替换分割符为函数
    print('subn-repl:', re.subn(pattern, repl, text, count=5, flags=re.I))  # subn-repl: ('变压器招标采购 500kw变压器 招标文件变压器', 2)


# 编译正则对象
    # compile函数 与 template函数 将正则表达式的样式编译为一个 正则表达式对象
     (正则对象Pattern),这个对象与re模块有同样的正则函数
3.9 re.compile(pattern=, flags)
3.10 re.template(pattern=, flags)
     #而template函数 与 compile函数 类似,只不过是增加了我们之前说的re.TEMPLATE 模式
     # 这个需要在以后的应用中再细细研究 ,在大师分析数据的时候应当会很有用。

# 其他
3.11 re.escape(pattern=)
   #re.escape(pattern) 可以转义正则表达式中具有特殊含义的字符,比如:. 或者 *
    re.escape(pattern) 看似非常好用省去了我们自己加转义,但是使用它很容易出现转义
    错误的问题,所以并不建议使用它转义,而建议大家自己手动转义
3.12 re.purge()
    #re.purge() 函数作用就是清除 正则表达式缓存
    在正则表达式函数之间,各个清洗函数之间,要使用re.purge()进行缓存清除
    re.purge()。。。。。。。重要

python re正则 python正则r的作用_正则表达式

 

五、匹配对象的方法
re.search() re.match()  re.fullmatch()这三个方法是返回一个可以匹配的对象
re.findall() , 返回的是一个匹配好的列表
因此,匹配对象的方法只适用于match\ search\ funmatch , 不适用于findall
常用的匹配对象的方法有两个, group() 和group()
  1、group方法
    方法定义: group(num = 0)
    方法描述:返回整个的匹配对象,或者特殊编号的字符组合
        test = '我12345 + abcde'
        pattern = re.compile("\w+")
        result = re.match(pattern, test)
        print(result)  # <re.Match object; span=(0, 6), match='我12345'>
        result1 = re.match(pattern, test).group()
        print(result1)  # 我12345
        # 如果想得到abcde,可以用()括起来
        pattern2 = re.compile("(\w+)\s+\++\s+(\w+)")
        result2 = re.match(pattern2, test).group()
        print(result2)  # 我12345 + abcde   
    分组的意义在于:我们不仅仅想得到匹配的整个字符串,我们还想得到整个字符串里面的特定
      子字符串。上例中,如果还想得到abcde,我们就可以用()括起来。
      因此,你可以对pattern进行任何的分组,提取你想得到的任何内容。
  2、groups方法
    方法定义: groups(default = None)
    方法描述:返回一个包含有所有匹配字组的元组,匹配失败则返回空元组。
        test = '我12345 + abcde'
        pattern_compile = re.compile("(\w+)\s+\++\s+(\w+)")
        result3 = re.search(pattern_compile, test).groups()  #groups()方法,返回元组
        print(result3)  # ('我12345', 'abcde'),返回的是一个元组

     一定注意: group返回的是一个字组   '我123你456'
              groups返回的是一个元组  ('我12345', 'abcde')
六、注意事项
1.字节串 与 字符串
    模式和被搜索的字符串既可以是 Unicode 字符串 (str) ,也可以是8位字节串 
    (bytes)。 但是,Unicode 字符串与8位字节串不能混用!
2.r 的作用
    对于正则表达式样式使用 Python 的原始字符串表示法;在带有 ‘r’ 前缀的字符
    串字面值中,反斜杠不必做任何特殊处理。
3.正则查找函数 返回匹配对象
    查找一个匹配项(search、match、fullmatch)的函数返回值都是一个 
    匹配对象Match ,需要通过match.group() 获取匹配值,这个很容易忘记。
    另外还需要注意:match.group() 与match.groups() 函数的差别!
4.重复使用某个正则
    如果要重复使用某个正则表达式,推荐先使用 re.compile(pattern)函数
     返回一个正则对象,然后复用这个正则对象,这样会更快!