Chinaunix首页 | 论坛 | 博客
  • 博客访问: 319730
  • 博文数量: 240
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 50
  • 用 户 组: 普通用户
  • 注册时间: 2016-08-04 18:14
文章分类

全部博文(240)

文章存档

2017年(8)

2014年(4)

2013年(15)

2012年(4)

2011年(14)

2010年(55)

2009年(140)

我的朋友

分类: Python/Ruby

2010-03-23 13:52:32

 

学习正则表达式,最好的教材是《精通正则表达式》,而要精通NFA正则表达式,使用了NFA引擎的python正则模块官方文档就是最好的教材,大部分的功能同样在其他使用传统NFA引擎的正则包里受到支持。

 

目前公开引擎流派的:

使用DFA引擎的程序主要有:awk,egrep,flex,lex,MySQL,Procmail等;
使用传统型NFA引擎的程序主要有:GNU Emacs,Java,ergp,less,more,.NET语言,PCRE library,Perl,PHP,Python,Ruby,sed,vi
使用POSIX NFA引擎的程序主要有:mawk,Mortice Kern Systems’ utilities,GNU Emacs(使用时可以明确指定)
使用DFA/NFA混合的引擎:GNU awk,GNU grep/egrep,Tcl

  1. 正则表达式语法

正则表达式(RE)模块的功能主要是设置一个字符串并搜索其中的字串;这个模块的功能让你检查一个特定的字符串,匹配给定的正则表达式(或正则表达式匹配特定的字符串,它可以归结为对同样的事情,一般情况下,NFA引擎是由表达式主导,而pythonre正是NFA引擎,从引擎的机制上来描述,应该是理解为拿正则表达式匹配特定的字符串;DNF引擎反之,详细可参考精通正则表达式一书关于正则引擎的章节)。

正则表达式可以被连接在一起,形成新的正则表达式,如果AB都是正则表达式,那么AB同时也是正则表达式。一般来说,如果一个串p匹配了A,另外一个串q匹配了B,那么串pq会匹配AB。这种情况不包含AB使用了低优先级描述
(非贪婪匹配模式),命名捕获组(反向引用)。因此,复杂的表达式可以很容易地从简单易建的子表达式来描述的。对于理论和正则表达式的执行细节,请参考本书的引用,或几乎任何编译器构造的文档。

这里包含关于正则表达式的进一步信息和详细报告、使用指南:

 

正则表达式可以同时包含元字符(直译为特殊字符,国内一般称为元字符)和普通字符。大多数普通字符,如“a”“1”“0”,是最简单的正则表达式,它们只是描述本身。您可以连接普通的字符,因此last匹配字符串'last'。 (在本节的其余部分,我们将按照这种格式来描述,表达式通常不带引号,和包含在单引号的字符串进行匹配。)

 

一些字符,如“|”,是特殊的字符。特殊符号会对普通字符进行分组或者影响临近的普通字符、表达式。

 

包括以下元字符:

.

Dot)在默认模式下,它匹配除了换行符号以外的任意字符。如果指定了DOTALL,那它将可匹配换行符。

 

^

Caret)匹配字符串的开始,即物理行的开始,在多行模式下,也可匹配换行符后的位置,即逻辑行的开始

 

$

匹配字符串的结尾或在字符串尾部的换行符之前的位置,在多行模式下,还可以匹配到一个新的行之前的位置。foo可以匹配'foo''foobar',而foo$只匹配'foo'。更有趣的是,在'foo1\nfoo2\n'中搜索foo.$,默认模式下匹配到'foo2',而在多行模式下,可匹配到'foo1''foo2'。不指定多行模式,$匹配物理行的结尾,而foo1为串的逻辑行之前的字符,所以未被匹配。

 

*

描述前边邻近的字符或子表达式,匹配0个或多个重复,因为许多重复是有可能的。ab*将匹配'a''ab',或者'a'后面跟大量的'b'

 

+

描述前边邻近的字符或子表达式,匹配1个或多个重复。ab+将匹配'a'和后面跟着不少于1个的b,但不单独匹配'a'

 

?

描述前边邻近的字符或子表达式,匹配0个或1个重复。ab?将匹配'a''ab'

 

*?+???

使用"*""+""?"这些量词描述符都是贪婪匹配的,它们会匹配尽可能多的字符。有时,这种行为并非是我们想要的,若使用<.*>去匹配'

title

',它将会匹配整个字符串,而不只是'

'。在量词描述符后面添加"?"后,会使匹配过程里,变为非贪婪模式,匹配尽可能少的字符。使用<.*?>去匹配之前的字符串,将只匹配

 

{m}

描述前边邻近的字符或子表达式,尝试匹配尽可能多的m个重复。例如,a{6}匹配6'a',不是5个。

 

{m,n}

描述前边邻近的字符或子表达式,尝试匹配尽可能多从m个到n个重复。例如a{3,5}将匹配35'a',省略m,默认为0,即是匹配下限为0个,省略n则是匹配上限为无限。例如,a{4,}将匹配'aaaab'里的4a或其中包含成千上万个'a',但最少应该有4'a',并不匹配'aaab',逗号不可省略,以免与之前介绍的描述符冲突。

 

{m,n}?

描述前边邻近的字符或子表达式,尝试匹配尽可能少从m个到n个重复。这是非贪婪版本的{m,n}。例如,在6个字符的字符串'aaaaaa'a{3,5}将匹配5'a',而a{3,5}?将匹配3'a'

 

\

用于转义元字符,或者简写标记的声明(将在下边谈论)。如果在python里你不适用raw原始字符串来作为表达式,请记住,表达式还需要为每个反斜杆前边在用一个反斜杆来转义。若转义序列并非由python作解析,那么\将会直接修饰之后的字符。但是如果由python来解释表达式,反斜杆应该重复2次。这比较复杂,不容易理解,所以强烈建议使用最简单的raw格式的原始字符串来写表达式。例如,r"aaa\(a\)"匹配'aaa(a)',假如使用普通字符串来编写表达式:"aaa\\(a\\)"

 

[]

用于描述一个字符组(台翻译为字符集)。字符组可以是由多个单独字符组成,也可以使用连字符-来表示字符范围。特殊字符在字符组里是无效的,只作为普通字符描述。例如,[akm$]是匹配'a''k''m''$'里的其中一个字符;[a-z]将匹配所有小写字母,[a-zA-Z0-9]将匹配所有字母和数字;简写标记也可以在字符组里描述。如果你想包含']'或者'-',那就在该字符前使用反斜杆转义,或者将它写在字符组的第一个,例如[]]匹配']',注意,假如同时需要匹配'-'']',就只能把其中一个放在第一位,另一个用反斜杆转义,推荐对所有不需要的元字符都使用反斜杆转义。您还可以匹配一个除了字符组里描述字符以外的字符,以脱字符'^'作为第一个字符,将标示这是一个排除型字符组,^在别的位置,只会匹配普通的'^'字符。例如,[^5]匹配除了5以外的字符;[^^]匹配除了脱字符以外的字符。

 

|

A|B,其中AB可以是任意的子表达式,该表达式将可匹配A或者B。表达式里可以使用任意数量的|进行多选分支的分隔。这可用于分组捕获等(见下文)。对目标字符串进行扫描时,|是从左到右的顺序进行分隔。当一个分支被完全匹配,那么该分支就会被接受,这以为着,一旦A匹配,B就永远不会被尝试匹配。即使B会匹配更长的字符串。换句话说,在|操作符里,是永远不会贪婪匹配的。要匹配一个普通字符|,可使用\|转义写法,或者用字符组包含:[|]

 

(...)

正则表达式会匹配括号内的字符,从开始字符到结束字符分为一个组,该组在捕获完成之后,可使用\数字来进行反向引用。需要匹配字符'('')'时,使用转义符进行转义'\(''\)',或者用字符组:[(][)]

 

(?...)

捕获组中可使用扩展功能符,在(之后使用?,在?之后描述进一步的语法含义。扩展通常不会进行新的捕获,(?P)除外。

以下是目前支持的扩展功能:

 

(?iLmsux)

(可以一个或者多个修饰符同时使用:'i''L''m''s''u''x')

该组匹配空字符串;在模块中,相应的设置标志:re.I,re.L,re.M,re.S,re.U,re.X。如果你需要在表达式中指定匹配标志,而不是通过编译函数来指定,这是非常有用的,编译标志将影响整个表达式。请注意,(?x)的标志改变表达式的书写规则,如果在该标志之后包含了空白字符,那空白字符将会被忽略。例如aa(?i)a可匹配'AaA'

 

(?:)

捕获组的无捕获版本。正则表达式会捕获任何在括号内的内容,但该捕获组不会捕获任何内容,也不可用于反向引用。一般用于做子表达式的界定符,例如给aa|b加限定:a(?:a|b)匹配'a'之后还有'a'或者'b',而不是原本的匹配'aa'或者匹配b

 

(?P...)

功能类似捕获组,但该组匹配后可通过一个名称来引用捕获内容。分组名必须是有效的python标识符,每个组名在一个表达式只能被用一次。一个没有声明组名的捕获组其实也是一个id编号组。所以在上面的例子里,也可以把组命名并且进行反向引用。例如,表达式是:(?P[a-zA-Z_]\w*),该匹配结果的对象可通过指定组名来返回,m.group('id')或者m.end('id'),并且在表达式中可用(?P=id)来进行反向引用,或者用\g进行替换文本。

示例:

>>> m = re.match('a(?Pb)cde','abcde') #命名捕获组id捕获b

>>> m.group() #获取所有成功匹配内容

'abcde'

>>> m.group('id') #获取id组捕获内容

'b'

>>> m.end('id') #获取id组成功匹配结束位置点

2

>>> m.end() #获取整个表达式成功匹配结束位置点

5

>>> m = re.match('a(?Pb)cde(?P=id)','abcdeb') #反向引用了id

>>> m.group()

'abcdeb'

>>> re.sub('a(?Pb)cde(?P=id)','ab\gh','abcdeb') 在替换中指定替换为id组的内容(b

'abbh'

 

(?P=name)

反向引用,匹配之前对应的命名组所捕获的内容。

 

(?#...)

注释,包含在该括号内的内容将被忽略。

 

(?=...)

如果当前位置可匹配...,那么匹配接下来的表达式,但这个匹配只是一个判断,它并不消耗、占有任何字符,这被称为后向断言(顺序肯定环视)。例如Isaac (?=Asimov)可以匹配Isaac,但它后边必须跟着'Asimov'

 

(?!...)

如果当前位置不可匹配...,那么匹配接下来的表达式。这是后向否定断言(顺序否定环视),例如,Isaac (?!Asimov) 会匹配 'Isaac ' ,当它后边不是跟着 'Asimov'的时候。

 

(?<=...)

如果当前位置点的前面符合某些条件,那么从这个点开始匹配接下来的表达式。这被称为前向断言(逆序肯定环视)(?<=abc)会找到一个匹配在字符串'abcdef'中,在匹配位置点向前检查三个字符,符合包含在断言里的描述的三个字符。断言所包含的表达式必须是固定长度的(不能使用量词修饰),这意味着a|b是被允许的,而a*a{3,4}是不允许的。请注意,使用后向断言永远不会从字符串开始进行匹配,你需要使用的函数可能是search(),而不是match(),因为match()是从字符串开头进行匹配,否则失败,而使用环视功能会导致该函数失败

>>> import re

>>> m = re.search('(?<=abc)def', 'abcdef')

>>> m.group(0)

'def'

 

This example looks for a word following a hyphen:

 

 

>>> m = re.search('(?<=-)\w+', 'spam-egg')

>>> m.group(0)

'egg'

 

(?...)

如果当前位置点的前面不符合某些条件,那么从这个点开始匹配接下来的表达式。这就是所谓的前向否定断言(逆序否定环视)。类似后向否定断言,所包含的表达式必须是固定长度的字符串。在前向否定断言里的表达式可能会在字符串开始被搜索。

 

(?(id/name)yes-pattern|no-pattern)

如果存在并捕获成功指定编号或命名的捕获组,就会尝试匹配yes-pattern,如果捕获失败,那么尝试匹配no-pattern|no-pattern是可省略的。例如,(<)?(\w+@\w+(?:\.\w+)+)(?(1)>)是一个匹配电子邮件地址的表达式,将匹配'<>' 或者 ''这样的格式,但不匹配'<'。该功能在2.4版本新加入。

 

元字符序列由'\'和下面列出的普通字符组成。如果字符不在下列,那么正则将会匹配第二个字符,例如\$匹配'$'

 

\number

引用对应编号的捕获组的内容。组编号从1开始。例如,(.+) \1匹配的是'the the''55 55',但不匹配'the end'。注意反向引用所引用的内容。这个元字符序列只能用来引用199之间的一个,如果第一个数字为0,或者是三位数,它不会被解释为反向引用,但会作为8进制数字。在字符组[]里,所有的元字符都被视为字符。

 

\A

匹配字符串的开始。

 

\b

匹配空字符串(匹配位置比较容易理解),但只在单词的开头或结尾。一个单词是由字母数字或下划线字符组成,因此一个单词的边界是空白或者非字母数字、不包括下划线。请注意,\b是指\w\W之间的边界,因此确切的字符集定义取决于UNICODELOCALE编译标志的值。在字符范围内,\b表示退格符,与python的字符串兼容。

 

\B

匹配空字符串(匹配位置比较容易理解),但当它不在单词的开始或结尾。这是和\b相反的,也受到LOCALEUNICODE的设置影响。

 

\d

UNICODE标志没有指定,匹配任何10进制数字,相当于[0-9]。带UNICODE标志时,它会匹配任何在unicode字符集中属于数字分类的字符。

 

\D

UNICODE标志没有指定,匹配任何非数字字符,相当于[^0-9]。带UNICODE标志时,它会匹配任何不在unicode字符集中属于数字分类的字符。

 

\s

LOCALEUNICODE标志没有指定时,匹配任何空白字符,这相当于[ \t\n\r\f\v]。带LOCALE标志时,它将匹配当前环境定义的空白符。如果带UNICODE标志,那么将匹配任何被划分为空白符的符号。

 

\S

LOCALEUNICODE标志没有指定时,匹配任何非空白字符,这相当于[^\t\n\r\f\v]。带LOCALE标志时,它将匹配当前环境定义的非空白符。如果带UNICODE标志,那么将匹配任何不被划分为空白符的符号。

 

\w

LOCALEUNICODE标志没有指定时,匹配任何字母数字字符、下划线,这相当于[a-zA-Z0-9_]。带LOCALE标志时,它将匹配当前环境定义的字母和[0-9_]。带UINCODE标志时,将匹配在unicode字符集里划分为字母的字符和[0-9_]

 

\W

LOCALEUNICODE标志没有指定时,匹配任何非字母数字字符、下划线,这相当于[^a-zA-Z0-9_]。带LOCALE标志时,它将匹配除了当前环境定义的字母、[0-9_]。带UINCODE标志时,将匹配除了在unicode字符集里划分为字母的字符、[0-9_]

 

\Z

匹配字符串的结束。

阅读(1876) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~