python re 模块及正则表达式调用认识1-(julius_lee)
最近用到正则表达式,虽然看了学习了一些,但是不成体系,没有深刻认识,所以来看官方文档学习下,进行一个半汉化的翻译吧,网上查了很多都不是特别全面,要不就不是纯粹用在python中。
http://docs.python.org/2/library/re.html?highlight=re#re
Both patterns and strings to be searched can be Unicode strings as well as 8-bit strings. 处理对象是unicode或者8位字符串与普通正则不同,python可以使用prefixed with'r' 即r‘XXXX 来代替反斜杠\ ,因为 "\\\\" 才能表示一个’\\‘ ,pattern string 大部分都 use Python’s raw string notation forregular expression patterns;
>>> print "\\n"
\n
>>> print r"\n"
\n
>>>
以上便是 r 的使用,可以减少一根反斜杠。
>>> len ('\n')
1
>>> len (r'\n')
2
因而字符串长度有些区别,会被加1;
中文范围 : [\u4e00-\u9fa5]
这里注意下 python 的re写的时候 要 u"[\u4e00-\u9fa5]" #确定正则表达式也是 unicode 的
7.2.1 正则表达式语法
RE对特定的字符串集进行匹配,这个模块提供了一个函数来检查特定的字符串是否与给定的表达式相匹配。
re可以串联起来形成新的正则表达式,如A,B分别是正则表达式,合起来AB也是正则表达式。基于此,复杂的正则表达式可以由简单的表达式组合而成,但是其中要排除边界条件,优先级,分组等影响;
下面进行正则格式的一个简介,更多信息参考:Regular Expression HOWTO.
正则表达式包含普通字符和特殊字符。普通字符直接匹配本身,比如 ‘last’ 匹配‘last’。
>>> print re.search('last','dfdfdlast;ini').group(0) #直接匹配
last
>>> print re.search('last','dfdfdladst;ini').group(0) #没有匹配成功,因为没有last
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
print re.search('last','dfdfdladst;ini').group(0)
AttributeError: 'NoneType' object has no attribute 'group'
>>> print re.search('last','dfdfdladst;ini') #没有匹配成功
None
>>>
一些字符比如‘|’,‘(’之类的是特殊字符,他们有时作为类的普通字符,有时又会影响他周围的正则表达式进行正确的匹配。正则表达式的pattern strings可能不包含空字节,但是可以通过 \ 数字 来实现对null byte 的表示,如‘\x00’。
>>> string = '\x00'+ r'\\'
>>> string
'\x00\\\\'
>>> print string
X #会有一个乱码
>>> print re.findall(r'[\x00\x5c]',string) #上面的意思应该是可以用ascii码来进行正则的书写;
['\x00', '\\', '\\']
>>>
#这个\x00是nul,\x5c是\,python表示方法不同而已,
对于汉字也可以书写正则,具体还没有仔细使用过,编辑器暂不支持。
[\xe000-\x9fcf]+ 就是查汉字的
特殊字符有:
‘.' ---一般情况下匹配除了newline以外的任何字符,如果 DOTALL 标志被指定,则匹配任何,包括newline换行符。
>>> print re.search(r'las.','dflast ini',re.S).group()#一个点匹配一个字符
last
>>> print re.search(r'las...','dflast ini',re.S).group()#3个点匹配3个字符,包含一个空格
last i
>>> print re.search(r'las.....','dflast \niop',re.S).group()#加了S可以匹配换行符\n
last
io
>>> print re.search(r'las.....','dflast \niop').group() #去掉标志位后出错
Traceback (most recent call last):
File "<pyshell#28>", line 1, in <module>
print re.search(r'las.....','dflast \niop').group()
AttributeError: 'NoneType' object has no attribute 'group'
>>>
为了看得直观,当然以上多个点可以用其它方式表示,后面讨论。
’^' ---匹配字符串的开始,在MULTILINE模式下,也匹配每一newline。
>>> print re.search(r'^last','lastert \nlastiop').group() #匹配字符串开始的第一个last
last
>>> print re.search(r'^last','llllastert\nlastiop',re.M).group() # M模式,匹配了第二行行首的last
last
>>> print re.search(r'^last','llllastert\nlastiop').group() #去掉M后匹配失败
Traceback (most recent call last):
File "<pyshell#37>", line 1, in <module>
print re.search(r'^last','llllastert\nlastiop').group()
AttributeError: 'NoneType' object has no attribute 'group'
‘$' ---匹配字符串的结尾或者字符串结尾的newline之前,在MULTILINE模式下,也匹配newline的前面部分。
>>> print re.search(r'.iop$','llllastermiop \nlastiop').group() #匹配结尾
tiop
>>> string = '''
llllastermiop
lastiop #为什么没有匹配tiop???????
werttr
'''
>>> print re.search(r'.iop$',string,re.M).group() #匹配换行符的前面部分
miop
为什么没有匹配tiop???????
foo匹配foo,也可以是foobar。而正则foo$只配foo.
>>> print re.search(r'foo$','foo').group()
foo
>>> print re.search(r'foo$','foobar').group() #匹配失败
Traceback (most recent call last):
File "<pyshell#56>", line 1, in <module>
print re.search(r'foo$','foobar').group()
AttributeError: 'NoneType' object has no attribute 'group'
>>>
在 'foo1\nfoo2\n' 中用foo.$进行匹配可以得到foo2,但在MULTILINE模式中得到的是foo1. 对$在’foo\n‘中进行searching,则会匹配到两个空白,一个在新行之前,一个在字符串的结尾。
>>> print re.search(r'foo.$','foo1\nfoo2\n').group()
foo2
>>> print re.search(r'foo.$','foo1\nfoo2\n',re.M).group()
foo1
>>>
>>> print re.search(r'$','foo1\nfoo2\n').group()
>>>
'*' ----匹配前一个字符0次或无限次
>>> print re.search(r'fo*','foooo').group()
foooo
>>> print re.search(r'fo*','f').group() #可以匹配前一个字符零次
f
>>>
’+‘----匹配前一个字符1次或无限次。ab+将匹配a之后的b至少一次。
>>> print re.search(r'fo+','foooo').group()
foooo
>>> print re.search(r'fo+','f').group()
Traceback (most recent call last):
File "<pyshell#67>", line 1, in <module>
print re.search(r'fo+','f').group()
AttributeError: 'NoneType' object has no attribute 'group'
>>>
’?‘----匹配前一个字符0次或一次。ab? 将匹配a 或者ab
>>> print re.search(r'fo?','foooo').group()
fo
>>> print re.search(r'fo?','f').group()
f
>>>
*?, +?,?? ---- '*','+','?'都是贪婪匹配限定符;尽可能多的匹配内容,但有时候没必要这样,’<.*>'对'<H1>title</H1>'进行匹配,将会匹配整个字符串不只是'<H1>',对其限定符后添加‘?’,这样就会得到非贪婪匹配或者得到最小匹配。尽可能的少匹配字符;用.*?在表达式之前,则会只匹配'<H1>'。
>>> print re.search(r'fo*?','foeeeerrfoeeb').group() # *匹配零次
f
>>> print re.search(r'fo*?','foooorrfooob').group()
f
>>> print re.search(r'fo+?','foeeeerrfoeeb').group() # + 匹配一次
fo
>>> print re.search(r'fo+?','foooorrfooob').group()
fo
>>> print re.search(r'fo??','foeeeerrfoeeb').group() # ?匹配一次
f
>>> print re.search(r'fo??','foooorrfooob').group()
f
>>>
>>> print re.search(r'<.*>','<H1>title</H1>').group()
<H1>title</H1>
>>> print re.search(r'<.*?>','<H1>title</H1>').group()
<H1>
>>>
对其限定符后添加‘?’,这样就会得到非贪婪匹配或者得到最小匹配
{m}--- 刚好匹配m次,不少也不多
>>> print re.search(r'fo{3}','foooo').group()
fooo
>>> print re.search(r'fo{2}','foooo').group()
foo
>>>
{m,n}---- 匹配正则m到n次,a{3,5} will match from 3 to 5'a' characters。m缺省时表示0,n缺省时表示无限次。a{4,}b will matchaaaab or a thousand'a' characters followed by ab, but notaaab.中间的逗号不能省略。
>>> print re.search(r'a{,4}b','aaab').group()
aaab
>>> print re.search(r'a{4,}b','aaab').group()
Traceback (most recent call last):
File "<pyshell#85>", line 1, in <module>
print re.search(r'a{4,}b','aaab').group()
AttributeError: 'NoneType' object has no attribute 'group'
>>>
{m,n}?----非贪婪模式,匹配最少的m次。For example, on the 6-character string 'aaaaaa', a{3,5} will match 5'a' characters,while a{3,5}? will only match 3 characters.
>>> print re.search(r'a{3,5}b','aaaaaab').group()
aaaaab
>>> print re.search(r'a{3,5}?b','aaaaaab').group() #这种后面还有字符的情况容易出错,实际还是以n来计算的
aaaaab
>>> print re.search(r'a{3,5}?','aaaaaab').group()
aaa
>>>
‘\' ----转义字符,用来匹配 *,?等等。不是使用raw string的情况下,Python also uses the backslash as an escape sequence in string literals;也就是不使用r'XXX时,要使用两次反斜杠才能表示一个反斜杠,用raw简单些。
>>> print re.search(r'a\*\?','aa*?b').group()
a*?
>>> print re.search('a\\*\\?','aa*?b').group()
a*?
>>>
[ ]---存放字符集,1)中括号中的字符可以是单个的,e.g. [amk] will match'a','m', or'k'.
>>> print re.search('[amk]','sdafgfhmrtykyy').group()
a
>>> print re.search('[amk].','sdafgfhmrtykyy').group()
af
>>> print re.search('[mka].','sdafgfhmrtykyy').group()
af
是或关系,匹配了a,就没有再匹配 m, k。
2)也可以是一段有序字符集,for example[a-z] will match any lower case ASCII letter,[0-5][0-9] will match all the two-digits numbers from 00 to 59, and[0-9A-Fa-f] will match any hexadecimal digit. 如果'-'字符放在了字符类的开头处或末尾处,该字符就会被当作一个普通字符来看待 ,(e.g.[a\-z]) or if it’s placed as the first or last character (e.g.[a-]),it will match a literal'-'.
>>> print re.search(r'[a-z]{3}','34asdfg98dfg').group()
asd
>>> print re.findall(r'[a-z]{3}','34asdfg98dfg')
['asd', 'dfg']
>>> print re.findall(r'[0-5][0-9]','34asFGg38dfg')
['34', '38']
[0-9a-fA-F] 匹配单个的十六进制数字,并且大小写不敏感。也可以结合范围定义与单个字符定义。[0-9a-fxA-FX] 匹配一个十六进制数字或字母X。再次强调一下,字符和范围定义的先后顺序对结果没有影响。
>>> print re.findall(r'[0-9A-Fa-f]','4A 80 7f 9z')#实际就是0-9,A-F,a-f 这一顺序数字和字符间进行匹配
['4', 'A', '8', '0', '7', 'f', '9']
>>> print re.findall(r'[0-9a-fxA-FX]{3}','we2rt4fxdef8AXgh')#可以添加特定的字符x,但是def被匹配了,why?
['4fx', 'def', '8AX']
>>>
>>> print re.findall(r'[a\-z]..','AXgh-erg5-6yfhka-jjhh') # a-z及其-都匹配,长度3个字符
['-er', '-6y', 'a-j']
>>> print re.findall(r'[a-]..','AXgh-erg5-6yfhka-jjhh')#z省略,匹配到最后
['-er', '-6y', 'a-j']
>>>
3)若其中含有特殊字符,则特殊字符作为普通字符对待,For example,[(+*)] will match any of the literal characters'(','+','*', or')'.
>>> print re.findall(r'[(+*)].','AXg(df+dgf4*dfg34)fdg')
['(d', '+d', '*d', ')f']
4)\w or\S也可以包含在其中,是否进行匹配主要取决于LOCALE or UNICODE mode 字符模式。
这个有单独用法
5)也可以进行反向匹配,first character of the set is'^', all the characters that are not in the set will be matched.[^5] will match any character except'5', and[^^] will match any character except'^'。
>>> print re.findall(r'[5].','AXgh-erg5-6yf')
['5-']
>>> print re.findall(r'[^5].','AXgh-erg5-6yf') #需要与匹配字符串开头区分开
['AX', 'gh', '-e', 'rg', '-6', 'yf']
>>>
6)为了匹配“] ",可以使用转义符或者放在前面,For example, both[()[\]{}] and[]()[{}] will both match a parenthesis.
>>> print re.findall(r'[()[\]{}].','AXg[h-er]g5-6y}f')
['[h', ']g', '}f']
>>>
’ | ‘---- 或匹配,A|B匹配任意一个,从左往右,也可以用于分组匹配,但是一旦A匹配,B将不再进行匹配。匹配自己时, To match a literal'|', use\|, or enclose it inside acharacter class, as in[|]
>>> print re.findall(r'[5|6].','AXgh-erg5-6yf')# B还是进行了匹配
['5-', '6y']
>>> print re.search(r'[5|6].','AXgh-erg5-6yf').group()
5-
>>> print re.findall(r'[5\|6].','AXgh-erg5\-6yf')
['5\\', '6y']
>>>
>>> re.findall(r'gr(a|r)y','sfdgrayfdfggrryfgg') #与分组连用时,返回括号内匹配的内容,并没有返回整个gray 或grry,why?
['a', 'r']
(...)---- 匹配圆括号中的正则表达式,表示分组的开始和结束,匹配以后分组的内容可以通过\编号来提取。
1.(…) 用来匹配符合条件的字符串。并且将此部分,打包放在一起,看做成一个组,group。
2. 而此group,可以被后续(正则表达式中)匹配时所引用。
此处我称其为 前向引用,即前面已经通过group定义好的字符串,你在后面需要引用。引用的方式,是通过\N,其中N是对应的group的编号。
编号为0的group,始终代表匹配的整个字符串;编号分别对应着1,2,3,…
>>> print re.search(r'(gra.)\w+(grr.)','sfdgrayfdfggrryfgg').group(1) #没有看见\编号,但是可以用group(number)来输出
gray
>>> print re.search(r'(gra.)\w+(grr.)','sfdgrayfdfggrryfgg').group(2)
grry
>>> print re.search(r'(gra.)\w+(grr.)','sfdgrayfdfggrryfgg').group(3)
Traceback (most recent call last):
File "<pyshell#65>", line 1, in <module>
print re.search(r'(gra.)\w+(grr.)','sfdgrayfdfggrryfgg').group(3)
IndexError: no such group
>>> print re.findall(r'(gra.)\w+(grr.)','sfdgrayfdfggrryfgg')
[('gray', 'grry')]
>>> print re.findall(r'(gra.)\w+(grr.)','sfdgrayfdfggrryfgg')
[('gray', 'grry')]
#To match the literals'(' or')',use\( or\), or enclose them inside a character class:[(][)].
>>> print re.search(r'(gr[(]a.)\w+(gr[)]r.)','sfdgr(ayfdfggr)ryfgg').group(1)
gr(ay
>>> print re.search(r'(gr[(]a.)\w+(gr[)]r.)','sfdgr(ayfdfggr)ryfgg').group(2)
gr)ry
>>> print re.search(r'(gr\(a.)\w+(gr\)r.)','sfdgr(ayfdfggr)ryfgg').group(1)
gr(ay
>>> print re.search(r'(gr\(a.)\w+(gr\)r.)','sfdgr(ayfdfggr)ryfgg').group(2)
gr)ry
>>>
(?...) -- 扩展符号,作为扩展语法,(?P<name>...) is the only exception to this rule。匹配圆括号中的正则表达式,并创建一个指定分组。
具体如下:
(?iLmsux)----该组匹配空串,其中的每个字母代表一种匹配模式;该字符设置了对应的标志,re.U (Unicode dependent),类似的有编译标志:
编译标志
编译标志让你可以修改正则表达式的一些运行方式。在 re 模块中标志可以使用两个名字,一个是全名如 IGNORECASE,一个是缩写,一字母形式如 I。(如果你熟悉 Perl 的模式修改,一字母形式使用同样的字母;例如 re.VERBOSE的缩写形式是 re.X。)多个标志可以通过按位 OR-ing 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
这有个可用标志表,对每个标志后面都有详细的说明。
标志 含义
DOTALL, S 使 . 匹配包括换行在内的所有字符
IGNORECASE, I 使匹配对大小写不敏感
LOCALE, L 做本地化识别(locale-aware)匹配
MULTILINE, M 多行匹配,影响 ^ 和 $
VERBOSE, X 能够使用 REs 的 verbose 状态,使之被组织得更清晰易懂
I
IGNORECASE
使匹配对大小写不敏感;字符类和字符串匹配字母时忽略大小写。举个例子,[A-Z]也可以匹配小写字母,Spam 可以匹配 "Spam", "spam", 或 "spAM"。这个小写字母并不考虑当前位置。
>>> print re.findall(r'g[a-r]{2}y','sfdgRAyfdfggRRyfgg',re.I)
['gRAy', 'gRRy']
>>> print re.findall(r'g[a-r]{2}y','sfdgRAyfdfggRRyfgg')
[]
>>>
L
LOCALE |
|