wojkxlq 发表于 2015-11-30 14:42:47

Python的正则表达式

  阅读目录


[*]简单介绍
[*]正则表达式元字符
[*]re模块
[*]实例
[*]参考资料

  今天学习了Python的正则表达式,开始觉得一点都看不懂!后面通过理解+实践 终于学会了正则表达式的基本用法


简单介绍


[*]正则表达式(regular expression)是一种用形式化语法描述的文本匹配模式,在需要处理大量文本处理的应用中有广泛的使用,IDE中的搜索常用正则表达式作为搜索模式
[*]如果学过linux\unix系统的都知道如sed、egrep、grep、awk这类的命令,它们是非常强大的文本处理工具,几乎所有的语言都有对正则表达式的支持,有的直接在语法中支持,有的使用扩展库的形式
[*]它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,就认为它"匹配"了,否则,该字符串就是不合法的
[*]Python的正则表达式就是使用的扩展库re,Python提供re模块,包含所有正则表达式的功能
[*]正则表达式也是用字符串表示的,所以首先了解如何用字符来描述字符!正则表达式中,如果直接给出字符,就是精确匹配

正则表达式元字符


[*]字符

  . 可以匹配任意字符                  'py.'可以匹配'pyc,pyo,py! ...'
\ 转义字符,使后一个字符改变原来的意思        'a\c.'可以匹配'a.c'

                             'a\\c'可以匹配'a\c'
  []字符集(字符类),可以逐个列出,也可以指定范围
   可以匹配一个数字、字母或者下划线
   +可以匹配至少由一个数字、字母或者下划线组成的字符串,比如'a100','0_Z','Py3000'
   *可以匹配由字母或下划线开头,后接任意个由一个数字、字母或者下划线组成的字符串
   {0, 19}更精确地限制了变量的长度是1-20个字符(前面1个字符+后面最多19个字符)



[*]预定义字符集(可以写在字符集[…]中)

  \d : 一个数字                 '0\d0'可以匹配'010,020,030 ...'
\D : 一个非数字[^\d]                'a\Dc'可以匹配'abc,azc ...'
\w : 字母或者数字             'a\wc'可以匹配'abc,adc,a1c...'
\W : 非字母,非数字[^\w]              'a\Wc'可以匹配'a c'
\s : 空白符(制表符,空格,换行符等)         'a\sc'可以匹配'a c'
\S : 非空白符[^\s]                  'a\Sc'可以匹配'a c'



[*]  边界匹配(不消耗待匹配字符串中的字符)


  ^ 字符或行的开始                    '^abc'可以匹配'abc'
$ 字符或行的结束                   'abc$'可以匹配'abc'
\A 字符串的开始                   '\Aabc'可以匹配'abc'
\Z 字符串结束                    'abc\Z'可以匹配'abc'
\b 一个单词开头或者末尾的空串            'a\b!bc'可以匹配'a!bc'
\B 不在一个单词开头或末尾的空串[^\b]       'a\Bc'可以匹配'abc'




import re
the_str = "This is some text -- with punctuation"
re.search(r'^\w+', the_str).group(0)         # This
re.search(r'\A\w+', the_str).group(0)        # This
re.search(r'\w+\S*$', the_str).group(0)      # punctuation
re.search(r'\w+\S*\Z', the_str).group(0)     # punctuation
re.search(r'\w*t\W*', the_str).group(0)      # text --
re.search(r'\bt\w+', the_str).group(0)     # text
re.search(r'\Bt*\B', the_str).group(0)     # 没有匹配

[*] 数量词(用在字符或(…)之后)

  * 匹配前一个字符0次或无限次              'ab*'可以匹配'ab,abc,abccc ...'
+ 匹配前一个字符1次或无限次              'ab+'可以匹配'abc,abccc'
?匹配前一个字符0次或1次                'ab?'可以匹配'ab,abc'
  {m,n} 之前元素最少出现m次,最多n次          'ab{1,2}c'可以匹配'abc,abbc'
{m} 之前的元素最少出现m次               'ab{2}c'可以匹配'abbc'





import re
re.search("^vforb?ox$", "vforox")            #True
re.search("^vforb?ox$", "vforbox")            #True   
re.search("^ab\*", "abbbbbbb")                  #True,返回"abbbbbbb"
re.search("^ab\*?", "abbbbbbb")                   #True,返回"a"
re.search("^ab+", "abbbbbbb")                     #True,返回"abbbbbbb"
re.search("^ab+?", "abbbbbbb")                  #True,返回"ab"

[*] 逻辑与分组

  | 左右表示任意一个                     'abc|def'可以匹配'abc,def'
() 表达式将作为分租 '(abc){2}'可以匹配'abcabc'
    分组作为一个整体,可以后接数量词表达式仅 | 在该组有效'a(123|456)c'可以匹配'a456c'


re模块


[*]有了以上的准备知识,我们就可以在Python中使用正则表达式了
[*]需要注意一个问题:Python的字符串本身也用\转义



>>> a = 'vforbox\\-010'                #python的字符串
>>> print a   #打印输出对象 a
vforbox\-010


[*] 上面的结果对应的正则表达式字符串不变,为了防止漏写或者更直观!这里强力推荐使用python的r前缀,这样的话就不用考虑转义问题了,并且写出来的表达式也更直观了




>>> a = r'vforbox\-010'                #python的字符串
>>> print a   #打印输出对象 a
vforbox\-010


[*]re.search(pattern,string,flag=0)

  搜索文本中的匹配的模式是最常用的,以模式和文本作为输入,如果有匹配则返回一个Match对象,否则返回None
每个Match对象包括相关的匹配信息:原字符串、正则表达式和匹配的文本在字符串中的位置




import re
pattern = "this"
text = "Does this text match the pattern?"
match = re.search(pattern, text)    # 返回一个Match对象
print match.re.pattern# 要匹配的正则表达式"this"
print match.string      # 匹配的文本"Does this match the pattern?"
print match.start()      # 匹配的开始位置 5
print match.end()       # 匹配的结束位置 9


[*]re.compile(pattern,flag=0)

  如果程序中频繁的使用到同一个正则表达式,每次使用的时候都写一遍正则表达式不仅不高效而且会大大增加出错的几率,re提供了compile函数将一个表达式字符串编译为一个RegexObject
模块级函数会维护已编译表达式的一个缓存,而这个缓存是的大小是有限制的!直接使用已经编译的表达式可以避免缓存查找的开销,并且在加载模块时就会预编译所有的表达式




import re
regex = re.compile("this")
text = "Does this text match the pattern?"
match = regex.search(text)
if match:
print "match"
match.group(0)        #返回匹配的字符串   
else:
print "not match"


[*]re.findall(pattern, string, flag=0)

  使用search会返回匹配的单个实例,使用findall会返回所有匹配的不重叠的子串




import re
pattern = 'ab'
text = 'abbaaabbbbaaaaaa'
re.findall(pattern, text)   # 返回['ab', 'ab']

[*]re.finditer(pattern, string, flag=0)

  finditer会返回一个迭代器,会生成Match实例,不像findall()返回字符串




import re
pattern = 'ab'
text = 'abbaaabbbbaaaaaa'
match = re.finditer(pattern, text)   
for m in match:
print m.start()
print m.end()

  以上的例子会分别输出两次匹配结果的起始位置和结束位置

  

  正则匹配默认采用的是贪婪算法,也就是说会re在匹配的时候会利用尽可能多的输入,而使用?可以关闭这种贪心行为,只匹配最少的输入
  例如:正则表达式"ab*"如果用于查找"abbbc",将找到"abbb"。而如果使用非贪婪的数量词"ab*?",将找到"a"

  

  用组来解析匹配,简单的说就是在一个正则表达式中有几个小括号()将匹配的表达式分成不同的组,使用group()函数来获取某个组的匹配,其中0为整个正则表达式所匹配的内容,后面从1开始从左往右依次获取每个组的匹配,即每个小括号中的匹配
  使用groups()可以获取所有的匹配内容




import re
the_str = "--aabb123bbaa"
pattern = r'(\W+)(+)(\d+)(\D+)'
match = re.search(pattern, the_str)   
match.groups()          # ('--', 'aabb', '123', 'bbaa')
match.group(0)          # '--aabb123bbaa'
match.group(1)          # '--'
match.group(2)          # 'aabb'
match.group(3)          # '123'
match.group(4)          # 'bbaa'

  python对分组的语法做了扩展,可以对每个分组进行命名,这样便可以使用名称来调用
  语法:(?P<name>pattern),使用groupdict()可以返回一个包含了组名的字典




import re
the_str = "--aabb123bbaa"
pattern = r'(?P<not_al_and_num>\W+)(?P<al>+)(?P<num>\d+)(?P<not_num>\D+)'
match = re.search(pattern, the_str)   
match.groups()                   # ('--', 'aabb', '123', 'bbaa')
match.groupdict()                # {'not_al_and_num': '--', 'not_num': 'bbaa', 'num': '123', 'al': 'aabb'}
match.group(0)                          # '--aabb123bbaa'
match.group(1)                        # '--'
match.group(2)                        # 'aabb'
match.group(3)                          # '123'
match.group(4)                        # 'bbaa'   
match.group('not_al_and_num')           # '--'
match.group('al')                     # 'aabb'
match.group('num')                      # '123' '
match.group('not_num')                # 'bbaa'

  以上的group()方法在使用的时候需要注意,只有在有匹配的时候才会正常运行,否则会抛错,所以在不能保证有匹配而又要输出匹配结果的时候,必须做校验

  

  在re中可以设置不通的标志,也就是search()和compile()等中都包含的缺省变量flag。使用标志可以进行完成一些特殊的要求,如忽略大小写,多行搜索等




import re
the_str = "this Text"
re.findall(r'\bt\w+', the_str)   # ['this']
re.findall(r'\bt\w+', the_str, re.IGNORECASE) # ['this', 'Text']

实例  


[*]用正则表达式来判断邮箱地址(通过交互)



#!/usr/bin/python
#coding=utf-8
#File Name: mail.py
#Author: vforbox
#Mail: vforbox@gmail.com
#Created Time: 2015-9-14
import re
t1=raw_input("Input e-mail address:")
if re.match(r'^+.*@++.(com|cn|org)$',t1):
print 'This is the correct e-mail address'
else:
print 'This is the wrong e-mail address'



# python mail.py
Input e-mail address:vforbox@gmail.com
This is the correct e-mail address
# python mail.py
Input e-mail address:vforbox@gmail.tk
This is the wrong e-mail address


[*]用正则表达式来判断国内区号电话号码(通过交互)



#!/usr/bin/python
#_*_coding:utf-8 _*_
#File Name: number.py
#Author: vforbox
#Mail: vforbox@gmail.com
#Created Time: 2015-9-14
import re
t1 =raw_input("输入 区号-号码:")
if re.match(r'^\d{3}-+\d{3,8}$', t1):
print '这是正确的电话号码'
else:
print '这是错误的电话号码'



# python number.py
输入 区号-号码:023-12345678
这是正确的电话号码
# python number.py
输入 区号-号码:023 12345678
这是错误的电话号码


参考资料


[*]廖雪峰 python2.7-正则表达式
[*]segmentfault团队-正则表达式1正则表达式2
[*]菜鸟教程-python-正则表达式
[*]http://www.cnblogs.com/Skins/custom/images/logo.gifAstralWind
  
页: [1]
查看完整版本: Python的正则表达式