python正则表达式学习笔记

原文参见
http://wiki.ubuntu.org.cn/Python%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%93%8D%E4%BD%9C%E6%8C%87%E5%8D%97
本文介绍适用于python 1.5版本(包括)以上的re模块
基本用法
>>> import re
>>> p=re.compile("word ")
>>> m=p.search("abcwords secondword third")
>>> dir(m)
['__copy__', '__deepcopy__', 'end', 'expand', 'group', 'groupdict', 'groups', 'span', 'start']
>>> m.span()
(15, 20)
>>> dir(p)
['__copy__', '__deepcopy__', 'findall', 'finditer', 'match', 'scanner', 'search', 'split', 'sub', 'subn']
>>> dir(re)
['DOTALL', 'I', 'IGNORECASE', 'L', 'LOCALE', 'M', 'MULTILINE', 'S', 'U', 'UNICODE', 'VERBOSE', 'X', '__all__', '__builtins__', '__doc__', '__file__', '__name__', 'compile', 'engine', 'error', 'escape', 'findall', 'finditer', 'match', 'purge', 'search', 'split', 'sub', 'subn', 'template']
python的元字符
基本和一般的正则表达式定义一样
"["和"]"
指定一个字符集合,可以枚举,也可以用"-"表示范围
如[3-6]:表示数字3,4,5,6的任意一个
[a-z]:表示所有小写字符
部分元字符在[]中失去特殊含义
"."
匹配除换行符以外的任意一个字符,re.DOTALL模式下例外
"*"
表示任意个重复出现
"+"
表示至少一个出现
"?"
表示至多出现一次
"{}"
表示出现的次数范围 {1,10},{,2},{3,}
"^"和"$"
分别表示开始和结尾
"|"
逻辑或
"()"
分组
"\"
转意符号,可将元字符表示为一般的字符 \$ ,\\,\(
常用的转意集合
\d      [0-9]
\D      [^0-9]
\s      任何空白字符;它相当于类  [ \t\n\r\f\v]
\S        [^\s]
\w      [a-zA-Z0-9_]
\W      [^\w]
\A      字符串首
\Z      字符串尾
\b      单词边界 [^a-zA-Z0-9]
\B      非单词边界 "\Babc" 匹配"sd abcdabc"第二个 "abc"
表示方法
    正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行.
    初始化时,正则表达式被当做python风格的字符串传入,如果有"\b""\t"之类的,
会被自动替换,有两种方法保持原义:
  • 转义符号表示 "abc\n" 表示为 "abc\\n"
    • 用raw格式字符串 r'abc\n'
      基本使用
      编译模式
      使用一个变量保存初始化结果,初始化将完成编译过程
      然后可以多次使用,如示例中所示
      模块级函数编译后立刻使用,系统会缓存编译结果
      >>> re.search("word ","abcwords secondword third").span()
      (15, 20)
      前者可以在运行时节省编译时间
      方法说明
      编译对象方法
      >>> p=re.compile(r'^[12][0-9]{1,2}')
      >>> dir(p)
      ['__copy__', '__deepcopy__', 'findall', 'finditer', 'match', 'scanner', 'search', 'split', 'sub', 'subn']
      match 从输入串的开始比较,看是否匹配,返回一个匹配对象或者None
      search 全文匹配,返回匹配对象或者None
      split 按照匹配的串将字符串分成子串,返回列表,可以控制子串数目
      sub 将匹配的串替换成指定的串
      subn 多返回替换次数
      findall 返回所由匹配的首坐标
      finditer 返回匹配的迭代器
      >>> m=p.search("234abcd")
      >>> dir(m)
      ['__copy__', '__deepcopy__', 'end', 'expand', 'group', 'groupdict', 'groups', 'span', 'start']
      匹配对象方法span 匹配的首末坐标元组
      group 匹配的组
      编译标志
      re.compile(reg,flag)
      标志及缩写
      含义
      DOTALL, S
      使 . 匹配包括换行在内的所有字符
      IGNORECASE, I
      使匹配对大小写不敏感
      LOCALE, L
      做本地化识别(locale-aware)匹配
      MULTILINE, M
      多行匹配,影响 ^ 和 $
      VERBOSE, X
      能够使用 REs 的 verbose 状态,使之被组织得更清晰易懂
      高级使用
      分组将一个串作为一个整体表示 r'(abc)*'匹配任意个abc的连续出现
      分组可以欠套,和vi的相似
      可以用\1,\2,...或者\g\g依此引用顺序定义的分组
      对不不会引用的分组用?:...表示,如(?:abc)表示(abc)被忽略
      可以用?P方式定义一个命名的分组 (?P[1-9][1-9]?)定义了分组名子为"id"\
      对命名的分组,可以用编号的方法引用:\k;也可以用\g方式引用,还可以用?P=name引用
      msg="03/06/2007"
      pattern = r"(?P\d+)/(?P\d+)/(\d+)"
      myre = re.compile(pattern)
      trans = r"\3年\g月\g日"
      ret = myre.sub(trans,msg)
      print ret
      2007年03月06日
      def trans(reg):
          tu = reg.groups()
          return "%s年%S月%s日"%(tu[2],tu[0].lstrip("0"),tu[1].lstrip("0"))#groups里面仍旧按照匹配的顺序排列
      ret = myre.sub(trans,msg)
      2007年3月6日
      肯定定界符?=...
      否定定界符?!...   匹配非的情况
      .*[.](?!bat$|exe$).*$
      匹配与替换"*"匹配默认是贪婪算法,接合?可以改为非贪婪算法,如*?,对于+,?,{m,n}的情况,需要实验确认是否是默认贪婪算法
      reg.sub(替换模型,原型[,替换次数])
      替换模型是一个原模式串的函数,可以是常量.接合分组标记,可以实现复杂的串转换
      工作原理如下:替换模型对象依此接收到从原型里面匹配到的匹配对象(reg.REG_Match 类型),然后根据该类型返回相应的替换串;re 将替换原型返回的串代替匹配到的串,继续下一次匹配.
      替换模型 非常灵活,例如

      count = 0
      def trans(reg):
      global count
      count = count + 1
      print type(reg)
      return "This is %s[%s] "%(count,reg.group())
      myre = re.compile(r"(?=\W?)http://(?:www\.)?\w+(?:\w+\.){0,2}\.com/")
      urls="Please see Google's Terms of Service posted at http://www.google.com/terms_of_service.html"
      res = myre.sub(trans,urls)
      out:
      print res
      out:Please see Google's Terms of Service posted atThis is 5[http://www.google.com/] terms_of_service.html
      findall() 返回列表,如果一次匹配中有有名分组,则列表的项成为分组组成的元组
      注意事项
      不要杀鸡用牛刀,跟据具体问题选用合适的工具.
      一般越特化的处理方式效率越高.
      参考string.replace string.join,string.split方法
         1 >>> m = re.match("([abc])+", "abc")
         2 >>> m.groups()
         3 ('c',)