正则表达式在每种语言中都会有,目的就是匹配符合你预期要求的字符串。
  
 
  Python正则表达式主要由re库提供,拥有了基本所有的表达式。
  
 
  16.1 Python正则表达式
  
  
     
      符号
       
     
      描述
       
     
      示例
       
     
      .
       
     
      匹配除换行符(\n)之外的任意单个字符
       
     
      字符串123\n456,匹配123:1.3
       
     
      ^
       
     
      匹配字符串开头
       
     
      abc\nxyz,匹配以abc开头的行:^abc
       
     
      $
       
     
      匹配字符串结尾
       
     
      abc\nxyz,匹配以xyz结束的行:xyz$
       
     
      *
       
     
      匹配多个
       
     
      hello\nword,匹配以w开头d结尾的单词:w*d
       
     
      +
       
     
      匹配1个或多个
       
     
      abc\nabcc\nadf,匹配abc和abcc:ab+
       
     
      ?
       
     
      匹配0个或1个
       
     
      abc\nac\nadd,匹配abc或ac:a?c
       
     
      [.]
       
     
      匹配中括号之中的任意一个字符
       
     
      abcd\nadd\nbbb,匹配abcd和add:[abc]
       
     
      [ .-.]
       
     
      匹配中括号中范围内的任意一个字符
       
     
      abcd\nadd\nbbb,匹配abcd和add:[a-c]
       
     
      [^]
       
     
      匹配[^字符]之外的任意一个字符
       
     
      abc\n\abb\nddd,不匹配abc和abb:[^a-c]
       
     
      {n}或{n,}
       
     
      匹配花括号前面字符至少n个字符
       
     
      1\n\12\n123\n1234,匹配123和1234:[0-9]{3}
       
     
      {n,m}
       
     
      匹配花括号前面字符至少n个字符,最多m个字符
       
     
      1\n\12\n123\n1234\n12345,匹配123和1234 :[0-9]{3,4}
       
     
      |
       
     
      匹配竖杠两边的任意一个
       
     
      abc\nabd\abe,匹配abc和abd:ab(c|d)
       
     
      \
       
     
      转义符,将特殊符号转成原有意义
       
     
      1.2,匹配1.2:1\.2,否则112也会匹配到
      
 
  
  
  
     
      特殊字符
       
     
      描述
       
     
      示例
       
     
      \A
       
     
      匹配字符串开始
       
     
      与^区别是:当使用修饰符re.M匹配多行时,\A将所有字符串作为一整行处理。
      
     
      abc123\nabc456,匹配abc123:\Aabc,^则都会匹配到
       
     
      \Z
       
     
      匹配字符串结束
       
     
      与\A同理
       
     
      \b
       
     
      匹配字符串开始或结束(边界)
       
     
      abc\nabcd,匹配a开头并且c结尾字符串:\babc\b
       
     
      \B
       
     
      与\b相反
       
     
      
       
     
      \d
       
     
      匹配任意十进制数,等效[0-9]
       
     
      1\n123\nabc,匹配1和123:[0-9],包含单个数字的都会匹配到,如果只想匹配1:\b[0-9]\b
       
     
      \D
       
     
      匹配任意非数字字符,等效[^0-9]
       
     
      1\n12\nabc,匹配abc:[^0-9]
       
     
      \s
       
     
      匹配任意空白字符,等效[\t\n\r\f\v]
       
     
      1\n a,注意a前面有个空格,匹配a:\s
       
     
      \S
       
     
      匹配任意非空白字符,等效[^\t\n\r\f\v]
       
     
      1\n a\n ,匹配1和a:\S
       
     
      \w
       
     
      匹配任意数字和字母,等效[a-zA-Z0-9_]
       
     
      1\n a\n ,匹配1和a:\w
       
     
      \W
       
     
      与\w相反,等效[^a-zA-Z0-9_]
       
     
      
       
     
      \n
       
     
      反向引用,n是数字,从1开始编号,表示引用第n个分组匹配的内容
       
     
      ff,匹配ff:(.)\1,即"ff"
      
 
  
  
  
     
      扩展正则表达式
       
     
      描述
       
     
      ( )
       
     
      匹配小括号中正则表达式或字符。用上面\n特殊字符引用。
       
     
      (?#...)
       
     
      注释小括号内的内容
       
     
      (?:...)
       
     
      不保存匹配的分组
       
     
      (?P<name>...)
       
     
      命名分组,name是标识名称,默认是数字ID标识分组匹配
       
     
      (?=...)
       
     
      匹配后面能匹配表的达式...,称为正先行断言
       
     
      (?!...)
       
     
      匹配后面不能匹配的表达式...,称为负先行断言
       
     
      (?<=...)
       
     
      匹配前面能匹配的表达式...,称为正后发断言
       
     
      (?<!...)
       
     
      匹配前面不能匹配的表达式...,称为负后发断言
       
     
      (?(id/name)Y/N)
       
     
      如果分组提供的id或name存在,则使用Y表达式匹配,否则N表达式匹配
      
  
  断言:断言就是一个条件,判断某个字符串前面或后面是否满足某种规律的字符串,不能引用。
  
  博客地址:http://lizhenliang.blog.51cto.com and https://yq.aliyun.com/u/lizhenliang QQ群:323779636(Shell/Python运维开发群) 
  
 
  16.2 re库
  
 
  re模块有以下常用的方法:
  
  
     
      方法
       
     
      描述
       
     
      re.compile(pattern, flags=0)
       
     
      把正则表达式编译成一个对象
       
     
      re.findall(pattern, string, flags=0)
      以列表形式返回所有匹配的字符串 
     
      re.finditer(pattern, string, flags=0)
       
     
      以迭代器形式返回所有匹配的字符串
       
     
      re.match(pattern, string, flags=0)
       
     
      匹配字符串开始,如果不匹配返回None
       
     
      re.search(pattern, string, flags=0)
       
     
      扫描字符串寻找匹配,如果符合返回一个匹配对象并终止匹配,否则返回None
       
     
      re.split(pattern, string, maxsplit=0, flags=0)
       
     
      以匹配模式作为分隔符,切分字符串为列表
       
     
      re.sub(pattern, repl, string, count=0, flags=0)
       
     
      字符串替换,repl替换匹配的字符串,repl可以是一个函数
       
     
      re.purge()
       
     
      清除正则表达式缓存
      
 
  参数说明:
  
 
  pattern   正则表达式
  
 
  string    要匹配的字符串
  
 
  flags     标志位的修饰符,用于控制表达式匹配模式
  
 
  标志位的修饰符,有以下可选项:
  
  
     
      修饰符
       
     
      描述
       
     
      r
      e.DEBUG 
       
     
      显示关于编译正则的debug信息
       
     
      re.I/re.IGNORECASE
       
     
      忽略大小写
       
     
      re.L/re.LOCALE
       
     
      本地化匹配,影响\w,\w,\b,\B,\s和\S
       
     
      re.M/re.MULTILINE
       
     
      多行匹配,影响^和$
       
     
      re.S/re.DOTAIL
       
     
      匹配所有字符,包括换行符\n,如果没这个标志将匹配除了换行符
       
     
      re.U/re.UNICODE
       
     
      根据unicode字符集解析字符。影响影响\w,\w,\b,\B,\d,\D,\s和\S
       
     
      re.X/re.VERBOSE
       
     
      允许编写更好看、更可读的正则表达式,也可以在表达式添加注释,下面会讲到
      
 
  
  
 
  16.2.1 re.compile()
  
 
  把正则表达式编译成一个对象,方便再次调用:
  
  
  
   >>> import re
   
  
   prog = re.compile(pattern)
   
  
   result = prog.match(string)
   
  
   等效于
   
  
   result = re.match(pattern, string)
   
  
 
  例如:检查字符串是否匹配
  
  
  
   >>> def displaymatch(match):
   
  
   ...     if match is None:
   
  
   ...         return None
   
  
   ...     return '<Match: %r, group=%r>' % (match.group(), match.groups())
   
  
   ...
   
  
   >>> valid = re.compile(r"^[a-c1-3]{3}$")
   
  
   >>> displaymatch(valid.match("a1b"))   # 可用
   
  
   "<Match: 'a1b', group=()>"
   
  
   >>> displaymatch(valid.match("a1b2"))  # 不可用
   
  
   >>> displaymatch(valid.match("bbb"))   # 可用
   
  
   "<Match: 'bbb', group=()>"
   
  
 
  16.2.1 match()
  
 
  例如:判断字符串开头是否匹配字符
  
  
  
   >>> m = re.match(r'hello', 'hello world')           
   
  
   >>> print m  # 匹配到字符串开头是hello
   
  
   <_sre.SRE_Match object at 0x7f56d5634030>
   
  
   >>> m = re.match(r'world', 'hello world')     
   
  
   >>> print m  # 没有匹配到
   
  
   None
   
  
 
  正则对象匹配方法:
  
 
       1)group([group1, ...])
  
  
  
   >>> m = re.match(r'(\w+) (\w+)', 'hello world')
   
  
   >>> m.group(0)    # 全部组匹配
   
  
   'hello world'
   
  
   >>> m.group(1)    # 第一个括号子组
   
  
   'hello'
   
  
   >>> m.group(2)    # 第二个括号子组
   
  
   'world'
   
  
   >>> m.group(1, 2) # 多个参数返回一个元组
   
  
   ('hello', 'world')
   
  
 
       通过分子重命名的名字来引用分组结果:
  
  
  
   >>> m = re.match(r'(?P<first_name>\w+) (?P<last_name>\w+)', 'hello world')     
   
  
   >>> m.group('first_name')
   
  
   'hello'
   
  
   >>> m.group('last_name')
   
  
   'world'
   
  
   # 命名组也可以引用他们的索引
   
  
   >>> m.group(1)
   
  
   'hello'
   
  
   >>> m.group(2)
   
  
   'world'
   
  
 
       如果一组匹配多次,只有最后一个匹配:
  
  
  
   >>> m = re.match(r"(..)+", "a1b2c3")
   
  
   >>> m.group(1)
   
  
   'c3'
   
  
 
       2)groups([default])
  
 
       返回一个元组包含所有子组的匹配。
  
  
  
   >>> m = re.match(r"(\d+)\.(\d+)", "24.1632")
   
  
   >>> m.groups()
   
  
   ('24', '1632')
   
  
 
       3)groupdict([default])
  
 
       返回子组名字作为键,匹配结果作为值的字典。
  
  
  
   >>> m = re.match(r"(?P<first_name>\w+) (?P<last_name>\w+)", "hello world")
   
  
   >>> m.groupdict()
   
  
   {'first_name': 'hello', 'last_name': 'world'}
   
  
 
       4)start()和end()
  
 
       例如:去掉邮件地址的某字符
  
  
  
   >>> email = "tony@163_126.com"
   
  
   >>> m = re.search(r"_126", email)
   
  
   >>> email[:m.start()] + email[m.end():]
   
  
   'tony@163.com'
   
  
 
  5)span()
  
 
       以列表形式返回匹配索引开始和结束值:
  
  
  
   >>> email = "tony@163_126.com"
   
  
   >>> m = re.search(r"_126", email)
   
  
   >>> m.span()
   
  
   (8, 12)
   
  
 
       6)pos和endpos
  
 
       返回字符串开始和结束索引值:
  
  
  
   >>> email = "tony@163_126.com"
   
  
   >>> m = re.search(r"_126", email)
   
  
   >>> m.pos
   
  
   0
   
  
   >>> m.endpos
   
  
   16
   
  
 
  16.2.3 search()
  
 
  search()方法也具备match()方法的正则对象匹配方法,区别是search()匹配到第一个后就返回并终止匹配。
  
 
  
例如:匹配第一个结果就返回
  
  
  
   >>> m = re.search(r"c", "abcdefc")
   
  
   >>> m.group()
   
  
   'c'
   
  
   >>> m.span()
   
  
   (2, 3)
   
  
 
  16.2.4 split()
  
 
  例如:以数字作为分隔符拆分字符串
  
  
  
   >>> m = re.split(r"\d+", "a1b2c3")       
   
  
   >>> m
   
  
   ['a', 'b', 'c', '']
   
  
 
  16.2.4 sub()
  
 
  例如:替换2016
  
  
  
   >>> m = re.sub(r"\d+", "2017", "the year 2016")
   
  
   >>> m
   
  
   'the year 2017'
   
  
 
  例如:repl作为一个函数
  
  
  
   >>> def repl(m):                         
   
  
   ...   return str(int(m.group('v')) * 2)     
   
  
   ...
   
  
   >>> re.sub(r'(?P<v>\d+)', repl, "123abc")
   
  
   '246abc'
   
  
 
  函数返回必须是一个字符串。
  
 
  16.2.5 findall()和finditer()
  
 
  例如:得到所有匹配的数字
  
  
  
   >>> text = "a1b2c3"
   
  
   >>> re.findall(r'\d+', text)
   
  
   ['1', '2', '3']
   
  
  
  
   >>> for m in re.finditer(r'\d+', text):
   
  
   ...   print m.group()
   
  
   ...
   
  
   1
   
  
   2
   
  
   3
   
  
 
  16.2.6 原始字符串符号"r"
  
 
  上面所看到的(r"\d+")其中的r代表原始字符串,没有它,每个反斜杠'\'都必须再加一个反斜杠来转义它。
  
 
  例如,下面两行代码功能上是相同的:
  
  
  
   >>> m = re.match(r"\W(.)\1\W", " ff ")
   
  
   >>> m.group()
   
  
   ' ff '
   
  
   >>> m = re.match("\\W(.)\\1\\W", " ff ")
   
  
   >>> m.group()
   
  
   ' ff '
   
  
   >>> m = re.match("\W(.)\1\W", " ff ")   
   
  
   >>> m.group()
   
  
   Traceback (most recent call last):
   
  
     File "<stdin>", line 1, in <module>
   
  
   AttributeError: 'NoneType' object has no attribute 'group'
   
  
 
  \W匹配第一个和最后一个空字符,(.)匹配第一个f,\1引用前面(.)匹配的结果(还是f),即是r"ff"
  
 
  16.3 贪婪和非贪婪匹配
  
 
  贪婪模式:尽可能最多匹配
  
 
  非贪婪模式,尽可能最少匹配,一般在量词(*、+)后面加个问号就是非贪婪模式。
  
  
  
   # 贪婪匹配
   
  
   >>> re.findall(r"<div>.*</div>", "<div>a</div><div>b</div><div>c</div>")
   
  
   ['<div>a</div><div>b</div><div>c</div>']
   
  
   # 非贪婪匹配
   
  
   >>> re.findall(r"<div>.*?</div>", "<div>a</div><div>b</div><div>c</div>")
   
  
   ['<div>a</div>', '<div>b</div>', '<div>c</div>']
   
  
   >>> re.findall(r"a(\d+)", "a123b")     
   
  
   ['123']
   
  
   >>> re.findall(r"a(\d+?)", "a123b")
   
  
   ['1']
   
  
   # 如果右边有限定,非贪婪失效
   
  
   >>> re.findall(r"a(\d+)b", "a123b")   
   
  
   ['123']
   
  
   >>> re.findall(r"a(\d+?)b", "a123b")  
   
  
   ['123']
   
  
 
  贪婪匹配是尽可能的向右匹配,直到字符串结束。
  
 
  非贪婪匹配是匹配满足后就结束。
  
 
  
16.3 了解扩展表达式
  
 
  以一个字符串来学习断言的用法:"A regular expression "
  
 
  1)(?=...)
  
 
  正先行断言,匹配后面能匹配的表达式。
  
 
  
有两个re字符串,只想匹配regular中的:
  
  
  
   >>> re.findall(r"..(?=gular)", "A regular expression") 
   
  
   ['re']
   
  
   # 再向后匹配几个字符说明匹配的regular中的。下面都会说明下,不再注释
   
  
   >>> re.findall(r"(?=gular).{5}", "A regular expression")
   
  
   ['gular']
   
  
 
  2)(?!...)
  
 
  负先行断言,匹配后面不能匹配表达式。
  
 
  只想匹配expression中的re字符串,排除掉regular单词:
  
  
  
   
>>> re.findall(r"re(?!g)", "A regular expression") 
   
  
   ['re']
   
  
   >>> re.findall(r"re(?!g).{5}", "A regular expression")
   
  
   ['ression']
   
  
 
  3)(?<=...)
  
 
  正向后行断言,匹配前面能匹配表达式。
  
 
  
只想匹配单词里的re,排除开头的re:
  
  
  
   >>> re.findall(r"(?<=\w)re", "A regular expression")
   
  
   ['re']
   
  
   >>> re.findall(r"(?<=\w)re.", "A regular expression")       
   
  
   ['res']
   
  
 
  在re前面有一个或多个字符,所以叫后行断言,正则匹配是从前向后,当遇到断言时,会再向字符串前端检测已扫描的字符,相对于扫描方向是向后的。
  
 
  
4)(?<!...)
  
 
  负向后行断言,匹配前面不能匹配的表达式。
  
 
  只想匹配开头的re:
  
  
  
   >>> re.findall(r"(?<!\w)re", "A regular expression") 
   
  
   ['re']
   
  
   >>> re.findall(r"(?<!\w)re.", "A regular expression")
   
  
   ['reg']
   
  
 
  
16.4 修饰符
  
 
  re.VERBOSE上面说明可能你还不太明白,怎么个更加可读呢,这就来看看,下面两个正则编译等效:
  
  
  
   >>> a = re.compile(r"""\d +  # the integral part
   
  
   ...                    \.    # the decimal point
   
  
   ...                    \d *  # some fractional digits""", re.X)
   
  
   >>> b = re.compile(r"\d+\.\d*")
   
  
 
  当你写的正则很长的时候,可以添加注释。
  
 
  
  
 
  Python正则表达式参考:https://docs.python.org/2/library/re.html