Python正则表达式和re模块

来源:互联网 发布:手机读取运动数据权限 编辑:程序博客网 时间:2024/05/10 03:35

原始字符串
在介绍正则表达式之前,先提及一下关于原始字符串的内容。原子字符串就是能够保证输入的字符与书写的方式保持一致。特别是再输入path的时候经常会遇到。

>>> path1 = 'c:\joe\nihao.py' #未进行字符串转义>>> print path1#c:\joe#ihao.py
>>> path2 = r'c:\joe\nihao.py'#用原始字符串进行转义>>> print path2c:\joe\nihao.py

\n代表换行的意思,在普通字符串中,反斜杠会有一些特殊的作用。如果不对前面的反斜杠进行转义,那么执行的效果会按照特殊字符的效果呈现,无法形成一个完整的path。而原始字符串并不会对反斜杠进行特殊对待,反斜杠的作用在原始字符串中将会消失。

当然我们也可以在反斜杠前面加一个反斜杠,指定某些反斜杠是没有特殊意义的。上面的路径也可以如下表示,也能达到同样的效果。

>>> path3 = 'c:\\joe\\nihao.py' #用反斜杠进行转义>>> print path3#c:\joe\nihao.py

正则表达式

什么是正则表达式?简单的来说就是一种可以用于匹配文本片段的模式。就跟SQL里面模糊查找的时候like后面的代码有点类似。比如SQL里面like ‘s%’ 表示以S开头的值。

Python里面用到正则表达式(regular expression)的模块叫做re,在使用之前要import re。正则表达式比较繁琐,但很重要,特别是在爬虫解析网站的时候,经常需要用到。之前也看过几次,都似懂非懂,每次需要用到的时候才知道其重要性,还得耐着性子去学。这次为了监督自己彻底地学习正则表达式,特意整理了一下python的正则表达式。


基本匹配规则

  • 通配符 (.)

字符集就是可以让用户自定义匹配的字符,用[ ]括住自定义的字符来表示字符集,这样在效率上来讲会有很大的提升。比如[abc]表示匹配a,b,c中的任意一个字符,’[abc]joe’能够匹配到’ajoe’,’bjoe’,’cjoe’。

>>> re.findall(r'[jy]o[eu]','hello, I am joe. Nice to meet you.') ['joe', 'you']
  • 字符集 ([ ])

在字符集中有一个很有趣的特点,一些大部分的特殊字符在字符集中不需要进行转义,比如像点号,问号,星号等。除了一下情况需要特别注意:

    脱字符(^)在开头表示否定运算,[^abc]表示除了a, b, c以外的字符。如果你想表示^, a, b, c 中的任意一个,需要写成[/^abc]或者不把^放在开头[a^bc]。    右中括号(])和横线(-)需要进行转义。 这个其实很简单,对比一下[a-z]和[a/-z]的区别,或者说[abc]de]和[abc/]de]的区别。
>>> re.findall(r'.o[^e]','hello, I am joe. Nice to meet you.') #转义前['lo,', 'to ', 'you']>>> re.findall(r'.o[/^e]','hello, I am joe. Nice to meet you.') #转义后['joe']

几种python自定义的字符集:
\d 匹配任何十进制数;它相当于类 [0-9]
\D 匹配任何非数字字符;它相当于类 [^0-9]
\s 匹配任何空白字符;它相当于类 [ “t”n”r”f”v]
\S 匹配任何非空白字符;它相当于类 [^ “t”n”r”f”v]
\w 匹配任何字母数字字符;它相当于类 [a-zA-Z0-9_]
\W 匹配任何非字母数字字符;它相当于类 [^a-zA-Z0-9_]

  • 选择符(|)

选择符就是表示选择,几个里面挑选一个。有时候我们仅仅只要匹配的字符串几种固定的模式,没有必要去设计一个字符集。比如我们只要去匹配‘cup’和‘cat’,那我们就可以写成‘cup|cat’的形式,当然也可以写三个或者跟多。建议在数量少,字符没有什么共同规则可寻的时候使用。

>>> re.findall(r'meet|joe|am','hello, I am joe. Nice to meet you.')['am', 'joe', 'meet']
  • 子模式(subpattern)

我们发现‘cup’和‘cat’并不是完全没有相似之处,至少都是c开头的嘛。所以我们还可以加入一个子模式去匹配,可以写成‘c(at|up)’的形式,但这个时候返回的只有括号里面的内容

>>> re.findall(r'e([le]|[t])','hello, I am joe. Nice to meet you.')['l', 'e']
  • 可选项(?)和重复

一个正则表达式的匹配模式中可以包含多个子模式,子模式可以通过加上问号来变成可选项。比如r’ (joe)?loves(python)?’可以用来匹配‘joelovespython’,‘joeloves’,‘lovespython’,‘loves’四种。
(pattern)?:允许出现一次或0次

子模式当然也可以重复:
(pattern)* :允许重复0次或多次。 包含了(pattern)?
(pattern)+ :允许重复1次或多次
(pattern){m,n} :允许重复m~n次


re模块转义问题处理

在re模块中也会遇到类似转义问题,同样需要对特殊字符进行转义处理。还是举例来说,比如我们想要匹配的字符是‘python.com’这个字符片断,我们需要设计一个什么样的pattern来匹配呢?直接用‘python.com’来匹配,的确可以匹配到‘python.com’,但也有可能匹配到‘pythonXcom’,(.)代表了所有。因此我们需要用‘python\.com’来进行匹配。用反斜杠来进行转义处理。

可这里为什么要用到两个转义符呢?因为这里需要涉及到两个级别的转义:1.通过python解释器转义;2. 通过re模块转义。简单的来说,第一个反斜杠是告诉python的解释器,跟在我后面那个反斜杠也是一个普通的反斜杠(在解释器层面上来说),不是特殊字符前面的反斜杠。第二个反斜杠到了re模块,就不再是一个纯洁的反斜杠了,是拿来转义的,它会告诉re模块跟在我后面的那个(.)就是一个(.), 不是什么不正经的(.)

这下就比较头痛了,感觉有点复杂。不过幸好我们好有原始字符串,用r‘python.com’可以进行替换‘python\.com’。在比较长或者比较复杂的模式下,原始字符串可以减少很多不必要的麻烦。


re 模块的函数

  • compile(pattern,flags)

compile()是根据包含的正则表达式的pattern,来创建一个模式对象。我是这么理解的,re模块就好比是java里面的一个类,compile()就相当于实例化一个对象,构造参数就是这个模式的正则表达式。构造的pattern可以调用re里面的search,match等函数。

pat = re.compile(pattern) pat.search(string)----------re.search(pattern,string)

上面两种写法是等同的,但是如果先转为模式对象,将实现更有效率的匹配。这样不需要在调用其它函数的时候,每次都进行转换。

  • search(pattern,string,flags)

search()会扫描整个字符串,并返回第一个成功的匹配字符串。比如在一下代码中搜索“as”,这个单词,会返回<_sre.SRE_Match at 0x49b2648>,返回结果等价True。如果没有找到,则会返回None。

>>> str = 'I would like go bak to HangZhou as soon as possible'>>> re.search(r'as',str)<_sre.SRE_Match object at 0x00000000030EBBF8> #返回MatchObject 对象>>> re.search(r'as',str).span()(32, 34) #返回第一个as的位置
  • match(pattern,string,flags)

match()和search()比较类似,match只会在字符串的开头进行匹配,比如match(‘joe’, ’joe92 is cute’)会返回true,match(‘joe’, ’excuse me? joe92 is cute?’)返回None

但是上面的方法匹配到的是joe92,如果我们仅仅要匹配joe,那么我们需要在后面加一个美元符号。match(‘joe$’, ’joe92 is cute’),那样就会返回None。

  • findall(pattern,string)

findall会返回所有与pattern一致的字段,返回的是一个list。如果pattern中包含了子模式,那么返回的会是由set组成的list。

>>> str = 'I would like go bak to HangZhou as soon as possible'>>> re.findall(r'a(.)(.)',str)[('k', ' '), ('n', 'g'), ('s', ' '), ('s', ' ')]
  • Split(pattern, string, maxsplit)

Split()函数是用来对字符串进行分割,分割的方式就是pattern。最后一个maxsplit可以设定最多进行几次分割。

>>> str = 'I would like go bak to HangZhou as soon as possible'>>> re.split(' ',str,maxsplit=3)['I', 'would', 'like', 'go bak to HangZhou as soon as possible']
  • escape(string)

这函数是非常实用的,它可以对字符串中所有可能被解释为正则表达式中的字符进行转义。通俗的来讲,你不想手动的输入转义符号,那么就可以调用这个函数。当然这个不一定100%准确,转义之后最好自己再检查一边。

>>>re.escape('www.google.com')'www\\.google\\.com'

re 中的组(group)

在re模块中类似于search,match函数,在找到匹配的字符串片段时,会返回一个MatchObject对象,组就是pattern中的子函数。组的顺序是有左侧括号的顺序决定的,组0是整个模式。

>>> str = 'I would like go bak to HangZhou as soon as possible'>>> re.search('I((.*)like(.)*)to',str).group()'I would like go bak to'>>> re.search('I((.*)like(.)*)to',str).group(1)' would like go bak '>>> re.search('I((.*)like(.)*)to',str).group(2)' would '

贪婪模式和非贪婪模式

在匹配过程中,pattern默认是贪婪的,什么意思呢?就是说我匹配以a开头的以s结尾的字符串片断,优先会去寻找那些长的片段。要想改成非贪婪模式,那么要在子模式的后面加一个?,如下所示:

>>> str = 'I would like go bak to HangZhou as soon as possible'>>> re.findall(r'a.*s',str)['ak to HangZhou as soon as poss'] #贪婪模式>>> re.findall(r'a.*?s',str)['ak to HangZhou as', 'as']  #非贪婪模式
0 0
原创粉丝点击