首页 > 代码库 > Using Regular Expressions in Python

Using Regular Expressions in Python

1. 反斜杠的困扰(The Backslash)

  有时候需要匹配的文本带有‘\‘,如‘\python‘,因为正则表达式有些特殊字符有特殊意义,所以需要前面加上‘\‘来消除特殊意义,这里匹配的正则表达式是‘\\python‘,这时候如果要编译这个正则表达式需要re.compile(‘\\\\python‘),因为在传递字符串的时候python本身就需要用‘\\‘来表示‘\‘,也就造成了反斜杠的泛滥。

  使用前缀‘r‘可以解决这个问题:’r‘之后的‘\‘只是这个字符本身而没有特殊意义,比如r‘\n‘表示两个符号‘\‘和‘n‘,而原来‘\n‘表示换行符,所以可以写成re.compile(‘\\python‘)

 

2. match的几种methods

match(): 判断RE是否从第一个字符开始匹配

search(): 判断是否从任意一个位置匹配(不管是否从第一个字符开始)

findall(): 找到RE匹配的所有子字符串,并以list的形式返回

finditer(): 找到RE匹配的所有子字符串,并以iterator的形式返回

 1 >>> p = compile([a-z]+) 2 >>> print p.match("") 3 None 4  5 >>> m = p.match(tempo) 6 >>> m.group() 7 tempo 8 >>> m.start(), m.end() 9 (0, 5)10 >>> m.span()11 (0, 5)12 13 >>> m = p.search(::: message)14 >>> m.group()15 message16 17 >>> p = re.compile(\d+)18 >>> it = p.finditer(12 drummers drumming, 11 pipers piping, 10 lords a-leaping)19 >>> for match in it:20 ...     print match.group()21 ...22 (0, 2)23 (22, 24)24 (29, 31)

 

 

3.

‘|‘: “或”,A|B表示匹配A或者B

‘^‘: 匹配行的开头,一般情况下只会匹配字符串的开头,如果在MULTILINE模式下则可以匹配每行的开头

1 >>> print re.search(^From, From Here to Eternity)2 <_sre.SRE_Match object at 0x...>3 >>> print re.search(^From, Reciting From Memory)4 None

 

 

‘\A‘: 只匹配字符串的开头

 

‘$‘: 匹配行的末尾,一般情况下只会匹配字符串的末尾,如果在MULTILINE模式下则可以匹配每个换行符

‘Z‘: 只匹配字符串的末尾

 

‘\b‘: 单词的边界,即单词的开头或者末尾,可以是空格或者非字母数字的字符

1 >>> p = re.compile(r\bclass\b)2 >>> print p.search(no class at all)3 <_sre.SRE_Match object at 0x...>4 >>> print p.search(the declassified algorithm)5 None6 >>> print p.search(one subclass is)7 None

 

  注意上面用来编译的正则前面要带‘r‘,因为在Python中‘\b‘是退格键,如下:

1 >>> p = re.compile(\bclass\b)2 >>> print p.search(no class at all)3 None4 >>> print p.search(\b + class + \b)5 <_sre.SRE_Match object at 0x...>

 

‘\B‘: 匹配不是单词边界

 

4. Grouping

  用‘()‘括起来表示分组,比如(ab)*可以匹配ab0次或者更多次。

  分组是有编号的,0表示整个RE,从左往右编号依次加一,只要看左括号的位置就行

 

1 >>> p = re.compile((a(b)c)d)2 >>> m = p.match(abcd)3 >>> m.group(0)4 abcd5 >>> m.group(1)6 abc7 >>> m.group(2)8 b

 

 

5. Non-capturing Groups

  ()里面跟着?:的是non-capturing group,一般用于一些分组后面不需要用到的时候

 

1 >>> m = re.match("([abc])+", "abc")2 >>> m.groups()3 (c,)4 >>> m = re.match("(?:[abc])+", "abc")5 >>> m.groups()6 ()

  原来编号1的分组在加上?:之后被忽略了,可以用在筛选一些没有用的分组。比较令人疑惑的是第2行m.groups()为什么是‘c‘,这里我觉得应该是贪婪模式尽量往后找的原因

 

6. Named Groups

  分组过多的时候编号难以记住,可以给分组加上一个名字,相当于一个“标签”,后面引用的时候可以直接通过名字来引用,用法是(?P<name>...)

1 >>> p = re.compile(r((?P<word>\b\w+\b)))2 >>> m = p.search( (((( Lots of punctuation ))) )3 >>> m.group(word)4 Lots5 >>> m.group(1)6 Lots

 

  还可以用来搜索与前面重复的字段:

1 >>> p = re.compile(r(?P<word>\b\w+)\s+(?P=word))2 >>> p.search(Paris in the the spring).group()3 the the

 

7. Lookahead Assertions

  (?=...) 需要在这个位置匹配括号里面之后的内容,匹配成功即可,不会消耗字符串的内容。

  (?!...) 与前一个相反,不能匹配括号里面之后的内容才能匹配成功,不会消耗字符串的内容。

  如在匹配带有扩展名的文件的时候,如果想要排除掉带有后缀.bat和.exe的文件,可以用 .*[.](?!bat$|exe$).*$

8. Splitting Strings

1 >>> p = re.compile(r\W+)2 >>> p2 = re.compile(r(\W+))3 >>> p.split(This... is a test.)4 [This, is, a, test, ‘‘]5 >>> p2.split(This... is a test.)6 [This, ... , is,  , a,  , test, ., ‘‘]

 

 

  如果使用括号将匹配内容括起来,那么在分割的时候匹配内容也会作为分割的一部分,否则匹配内容会被忽略。如上面通过空格将单词分开,加了括号之后空格也会记录为结果。

  .split()函数可以加进参数maxsplit表示最多分割几段,如:

 

1 >>> p = re.compile(r\W+)2 >>> p.split(This is a test, short and sweet, of split().)3 [This, is, a, test, short, and, sweet, of, split, ‘‘]4 >>> p.split(This is a test, short and sweet, of split()., 3)5 [This, is, a, test, short and sweet, of split().]

 

9. Search and Replace

  p = re.compile(‘...‘) , p.sub(replacement, string, [count = 0])

  string是原来用来被查找替换的字符串,replacement是查找到之后替换的内容,count是最多替换的个数,默认是0表示全部替换

1 >>> p = re.compile( (blue|white|red))2 >>> p.sub( colour, blue socks and red shoes)3 colour socks and colour shoes4 >>> p.sub( colour, blue socks and red shoes, count=1)5 colour socks and red shoes

 

  subn()使用方法类似,但是会同时返回找到替换的个数

1 >>> p = re.compile( (blue|white|red))2 >>> p.subn( colour, blue socks and red shoes)3 (colour socks and colour shoes, 2)4 >>> p.subn( colour, no colours at all)5 (no colours at all, 0)

 

 

  之前有命名分组的使用方法,(?P<name>...),后面想替换成这个分组的内容可以用\g<name>来替换,或者替换成第2组的内容可以用\2,但是替换成第2组内容后面再加上一个0就会写成\20,会与第20组产生误会,所以有另一个写法是\g<2>,下面例子用了这3种方法,将所有的section替换成subsection

1 >>> p = re.compile(section{ (?P<name> [^}]* ) }, re.VERBOSE)2 >>> p.sub(rsubsection{\1},section{First})3 subsection{First}4 >>> p.sub(rsubsection{\g<1>},section{First})5 subsection{First}6 >>> p.sub(rsubsection{\g<name>},section{First})7 subsection{First}

 

 

  还有一种更复杂的方法是用一个函数进行替换,每次会对match到的内容进行一定的操作,如下面将数字转化为16进制的时候,首先将match到的内容作为参数传进函数进行处理再返回16进制数

1 >>> def hexrepl(match):2 ..."Return the hex string for a decimal number"3 ...value =http://www.mamicode.com/ int(match.group())4 ...return hex(value)5 ...6 >>> p = re.compile(r\d+)7 >>> p.sub(hexrepl, Call 65490 for printing, 49152 for user code.)8 Call 0xffd2 for printing, 0xc000 for user code.