Python基础:28正则表达式

一:概述

        正则表达式(RE)为高级文本模式匹配,以及搜索-替代等功能提供了基础。正则表达式(RE)是一些由字符和特殊符号组成的字符串,它们能匹配多个字符串。Python通过标准库的re模块支持正则表达式。

        在Python中,有两种主要方法完成模式匹配:搜索(searching)和匹配(matching)。搜索是在字符串任意部分中查找匹配的模式;而匹配是指判断一个字符串能否从起始处全部或部分的匹配某个模式。搜索通过search()函数或方法来实现,而匹配是match()函数或方法实现的。

 

二:正则表达式与原始字符串

        正则表达式使用反斜杠”\”表明特殊字符,或者用来转义。这与Python中的用途是相冲突的,Python中字符串也是用”\”来表达相同的作用。比如,为例匹配字面上的反斜杠”\”,那么正则表达式的模式必须写成”\\\\”,这是因为匹配”\”的正则表达式为\\,该表达式做为python的字符串必须写成”\\\\”,即对每个反斜杠”\”进行转义。

        解决这种问题的方法是使用Python中的原始字符串。在原始字符串中,每个字符都不再有特殊的用途而表现为其字面的意思。比如r”\n”就是包含”\”和”n”两个字符的字符串,而”\n”是表明换行符的一个字符。一般情况下都是使用原始字符串来表示正则表达式的模式。

 

三:re模块

        re模块定义了一些函数,常量和异常。其中很多函数就是已编译的正则表达式对象(regex objects)方法的简化版本。它们具有相同的名称。总结如下表:

函数/方法

描述

re 模块的函数

compile(pattern,flags=0)

对正则表达式模式pattern 进行编译,flags 是可选标志符,并返回一个regex对象

re模块的函数和regex对象的方法

match(pattern, string, flags=0)

尝试用正则表达式模式pattern 匹配字符串string,flags 是可选标志符,如果匹配成功,则返回一个匹配对象;否则返回None

search(pattern, string, flags=0)

在字符串string 中查找正则表达式模式pattern 的第一次出现,flags 是可选标志符,如果匹配成功,则返回一个匹配对象;否则返回None

findall(pattern, string [,flags])

在字符串string 中查找正则表达式模式pattern 的所有(非重复)出现返回一个匹配对象的列表

finditer(pattern,string[, flags])

和findall()相同,但返回的不是列表而是迭代器;对于每个匹配,该迭代器返回一个匹配对象

split(pattern, string, max=0)

根据正则表达式pattern中的分隔符把字符string 分割为一个列表,返回成功匹配的列表,最多分割max 次(默认是分割所有匹配的地方)。

sub(pattern, repl, string, max=0)

把字符串string 中所有匹配正则表达式pattern 的地方替换成字符串repl,如果max 的值没有给出,则对所有匹配的地方进行替换(另外,请参考subn(),它还会返回一个表示替换次数的数值)。

group(num=0)

返回全部匹配对象(或指定编号是num 的子组)

groups()

返回一个包含全部匹配的子组的元组(如果没有成功匹配,就返回一个空元组)

 

        1:re.compile(pattern, flags=0)

        该函数将pattern编译成一个正则表达式对象,在模式匹配之前,正则表达式模式必须先被编译成正则表达式对象。这些对象具有和模块函数重名的方法。比如match和search等。

        prog = re.compile(pattern)

        result = prog.match(string)

等价于

        result = re.match(pattern, string)

        当需要多次使用同一正则表达式进行匹配时,使用re.compile编译成正则表达式对象更有效率。

        Python程序中,会对最近使用过re.match,re.search或re.compile的模式的编译版本进行缓存。所以如果只是较少次的匹配,可以无需使用编译版本。

 

        flags参数可以改变表达式的行为。比如下面的值:

        re.I或re.IGNORECASE:正则匹配不区分大小写,因此像[A-Z]也能匹配小写字母。

 

        re.M或re.MULTILINE:当指定时,模式字符^匹配字符串的开头以及每个行的开头(每个换行符之后); 模式字符$匹配字符串的末尾以及每一行的结尾(每个换行符之前)。默认情况下, ^只匹配字符串的开始,$只匹配字符串的末尾和字符串末尾换行符(如果有的话)之前的位置。

 

        re.S或re.DOTALL:使.特殊字符可以匹配任何字符,包括换行符;如果没有此标志, .不能匹配换行符。

 

        2:re.search(pattern, string, flags=0)

        在string中寻找能与pattern相匹配的第一个位置,并返回一个MatchObject实例。如果在string中找不到匹配的地方,则返回None。

 

        3:re.match(pattern, string, flags=0)

        在string的开头寻找与pattern匹配的字符串,并返回相应的MatchObject实例。如果找不到匹配的位置,则返回None。

注意,即使是MULTILINE模式,re.match也仅仅匹配字符串的开头,而不是每一行的开头。

 

        4:re.split(pattern, string, maxsplit=0, flags=0)

        使用pattern分割字符串string。注意,如果patter中使用了括号进行分组的话,则所有pattern中的分组也会作为结果列表中的一部分返回。

        如果给定了maxsplit参数,则最多会分割maxsplit次,剩余的字符串作为列表的最后一个元素。例子如下:

>>> re.split('\W+', 'Words,  words,  words.')

['Words', 'words', 'words', '']

 

>>> re.split('\W+', '...Words, words, words.')

['', 'Words', 'words', 'words', '']

 

>>> re.split('(\W+)','Words, words, words.')

['Words', ', ', 'words', ', ', 'words', '.', '']

 

>>>re.split(r'(abc):(123)4(56)', 'aaabc:123456defghikabc:123456lll')

['aa','abc', '123','56', 'defghik', 'abc','123', '56', 'lll']

 

>>> re.split('\W+', 'Words, words, words.',1)

['Words', 'words, words.']

 

>>> re.split('[a-f]+', '0a3B9',flags=re.IGNORECASE)

['0', '3', '9']

 

        注意,如果模式中具有分组,并且该分组匹配了字符串的开头,则返回列表的第一个元素会是一个空字符串。如果该分组匹配了字符串的结尾也一样

>>> re.split('(\W+)','...words, words...')

['',  '...',  'words',  ', ',  'words',  '...',  '']

 

>>> re.split('\W+','...words, words...')

['', 'words', 'words', '']

 

>>> re.split(r'(abc)d','abcdhehehabcdheheabcd')

['', 'abc', 'heheh', 'abc', 'hehe', 'abc', '']

 

        注意,如果模式无法匹配,则split将不会分割字符串

>>> re.split('x*', 'foo')

['foo']

 

>>> re.split(r'(a):(1)',  'aaabc:123456defghikabc:123456lll')

['aaabc:123456defghikabc:123456lll']

 

        5:re.findall(pattern, string, flags=0)

        返回string中所有非重叠的匹配pattern的子串,返回结果为一个列表。如果pattern中具有一个或多个分组,则返回一个分组的列表,如果有多个分组,则列表中每一个元素都是一个元组。

 

>>> re.findall(r"abc", "hhhhhhh")

[]

>>> re.findall('a','ASDaDFGAa')

['a', 'a']

>>> re.findall(r"aba","ababacabababa")   //非重叠                

['aba', 'aba', 'aba']

 

>>> re.findall(r"(a)(b)(c)", "abcdefabcefjgakjbclkabc")//分组

[('a', 'b', 'c'), ('a', 'b', 'c'), ('a', 'b', 'c')]

 

>>> re.findall(r"(a)bc","abcdefabcefjgakjbclkabc")

['a', 'a', 'a']

 

        6:re.sub(pattern, repl, string, count=0, flags=0)

        将string中,匹配pattern的非重叠子串替换为repl,并将替换后的字符串返回。如果string中没有匹配pattern的子串,则返回原始的string。

        可选的count参数表明最大替换次数,他必须是非负数,如果为0,则表示所有匹配的子串都进行替换。

 

        repl可以是字符串,也可以是函数。如果它是一个字符串,其中的反斜杠转义字符都会被预先处理。因此,”\n”将会转换为一个换行符,”\r”将会转换为回车符。未知的转义字符比如\j会保留原样。其中的向后引用,比如”\6”,将会替换为pattern中的相应分组。

        \g<name>是针对(?P<name>...)定义的分组名的匹配。\g<number>则针对分组号;因此\g<2>等价于\2,不同的是,像\g<2>0这样的写法具有更明确的意义。\20引用的分组20,而不是引用分组2之后跟着字符’0’。\g<0>代表整个子串。

 

        例子如下:

>>> re.sub("abc", "ABC","hhhh")

'hhhh'

 

>>> astr = re.sub(r"def\s+([a-zA-Z_]\w*)\s*\(\s*\):",  r'static PyObject*\npy_\1(void)\n{',   "def myfunc():")

>>> astr

'static PyObject*\npy_myfunc(void)\n{'

>>> print astr

static PyObject*

py_myfunc(void)

{

 

>>>bstr = re.sub(r"def\s+([a-zA-Z_]\w*)\s*\(\s*\):",  'static PyObject*\npy_\1(void)\n{',  "defmyfunc():")

>>>bstr

'static PyObject*\npy_\x01(void)\n{'

>>> print b

static PyObject*

py_  (void)

{

 

>>> astr = re.sub("abc","ABC", "abcdefabc")

>>> astr

'ABCdefABC'

>>>

>>> astr = re.sub("abc", "\n", "abcdefabc")  

>>> astr

'\ndef\n'

>>> len(astr)

5

>>> print astr

 

def

 

>>> bstr = re.sub("abc", r"\n", "abcdefabc")

>>> bstr

'\ndef\n'

>>> len(bstr)

5

>>> print bstr

 

def

 

>>> 

>>> astr = re.sub("abc","\j", "abcdefabc")

>>> astr

'\\jdef\\j'

>>> print astr

\jdef\j

 

>>>re.sub(r'\sAND\s', ' & ', 'Baked BeansAnd Spam', flags=re.IGNORECASE)

'Baked Beans & Spam'

 

        如果repl是个函数,则在找到string中的非重叠匹配子串时调用该函数,该函数以一个匹配对象为参数,并且返回替换后的子串。比如:

>>> def dashrepl(matchobj):

...     ifmatchobj.group(0) == '-': return ' '

...     else: return '-'

 

>>> re.sub('-{1,2}', dashrepl,'pro----gram-files')

'pro--gram files'

 

四:匹配对象(Match Objects)

        匹配对象是在match()或search()被成功调用之后所返回的结果。它的布尔值始终都是True。匹配对象有两个主要方法:group() 和 groups()。

 

        1:group([group1, ...])

        返回一个或多个匹配的子组。如果只有一个参数,则返回一个字符串,如果有多个参数,则返回一个元组,其中的每个元素就是匹配分组的字符串。

        如果没有参数,group1默认为0,则会返回整个匹配的字符串。如果group号是负数,或者大于模式中定义的子组,则会引发IndexError异常。

        如果模式中的某个分组没有匹配,则其相应的结果为None如果模式中的某个分组匹配了多次,则返回最后一次匹配。

>>> m = re.match(r"(\w+) (\w+)", "Isaac Newton, physicist")

>>> m.group(0)       # The entire match

'Isaac Newton'

>>> m.group(1)       # The first parenthesized subgroup.

'Isaac'

>>> m.group(2)       # The second parenthesized subgroup.

'Newton'

>>> m.group(1, 2)    # Multiple arguments give us a tuple.

('Isaac', 'Newton')

 

>>>m = re.search("(abc)(def)(cao)?","hhabcdeflkabcj")   //g3 notmatch

>>> m.group()

'abcdef'

>>> m.group(1,2,3)

('abc', 'def', None)

 

>>> m = re.match(r"(..)+", "a1b2c3")  # Matches 3 times.

>>> m.group(1)                        # Returns only the lastmatch.

'c3'

 

        如果正则表达式使用了(?P<name>...)语法,则group的参数也可以是相应的分组名。如果某个字符串在模式中并非某个分组名,则会引发IndexError异常。

>>> m = re.match(r"(?P<first_namehh>\w+) (?P<last_name>\w+)","Malcolm Reynolds")

>>> m.group()

'Malcolm Reynolds'

>>> m.group('first_namehh')

'Malcolm'

>>> m.group('first_name')

Traceback (most recent call last):

 File "<stdin>", line 1, in<module>

IndexError: no such group

>>> m.group('last_name')

'Reynolds'

 

        命名分组同样也可以通过组号来引用:

>>> m.group(1)

'Malcolm'

>>> m.group(2)

'Reynolds'

 

        2:groups([default])

        返回一个包含所有匹配子组的元组,如果某些分组没有匹配,则相应的元素置为None,除非给定了default参数。如果模式中没有分组,则返回空元组。例子如下:

>>> m = re.match(r"(\d+)\.(\d+)", "24.1632")

>>> m.groups()

('24', '1632')

 

>>> m = re.match(r"(\d+)\.?(\d+)?", "24")

>>> m.groups()      #Second group defaults to None.

('24', None)

>>> m.groups('0')   # Now,the second group defaults to '0'.

('24', '0')

 

        3: start([group])    end([group])

        返回匹配分组的子串的起始和结束的索引。默认情况下group为0。如果group没有参与匹配,则返回-1。

        如果分组g确实参与了匹配,则g匹配的子串为:m.string[m.start(g):m.end(g)]。例子如下:

>>>m = re.search("(abc)(def)(ccc)?", "hhhabcdefqie")

>>>m.start()

3

>>>m.end()

9

 

>>>m.start(1)

3

>>>m.end(1)

6

 

>>>m.start(2)

6

>>>m.end(2)

9

 

>>>m.start(3)

-1

>>>m.end(3)

-1

 

>>>email = "tony@tiremove_thisger.net"

>>>m = re.search("remove_this", email)

>>>email[:m.start()] + email[m.end():]

'tony@tiger.net'

 

        4:string, 传递给match或者search的字符串

>>>m = re.search("abc", "hhabchh")

>>>m.string

'hhabchh'

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值