Python3 re模块

正则表达式(Regular Expression)是字符串处理的常用工具,通常被用来检索、替换那些符合某个模式(Pattern)的文本。很多程序设计语言都支持正则表达式,像Perl、Java、C/C++。在 Python 中是通过标准库中的re 模块 提供对正则的支持。


一、正则表达式介绍

在使用 re 模块之前,先来了解一下正则表达式的基本语法。

1)用途

通过使用正则表达式,可以:

  • 测试字符串内的模式。—— 例如,可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式。这称为数据验证。

  • 替换文本。—— 可以使用正则表达式来识别文档中的特定文本,完全删除该文本或者用其他文本替换它。

  • 基于模式匹配从字符串中提取子字符串。—— 可以查找文档内或输入域内特定的文本。

2)语法

本文主要介绍正则的基本语法以及 re 模块的使用,不包括如何编写高效的正则表达式、如何优化正则表达式,这些主题请看其他教程。

下图列出了Python支持的一些正则表达式元字符和语法:

3)贪婪模式与非贪婪模式

“贪婪模式”总是尝试匹配尽可能多的字符;“非贪婪模式”则相反,总是匹配尽可能少的字符。例如,用"ab*"如果用于查找"abbbc",将找到"abbb"。而如果使用非贪婪的数量词"ab*?",将找到"a"。


二、使用 re 模块

下面我们开始来使用 re 模块。

1)编译正则表达式

re 模块提供了 re.compile() 函数将一个字符串编译成 pattern object,用于匹配或搜索。函数原型如下:

  1. re.compile(pattern, flags=0)  
re.compile() 还接受一个可选的参数 flag,用于指定正则匹配的模式。关于匹配模式,后面将会讲到。
  1. p = re.compile('ab*', re.IGNORECASE)  

2)反斜杠的困扰

在 python 的字符串中,\ 是被当做转义字符的。在正则表达式中,\ 也是被当做转义字符。这就导致了一个问题:如果你要匹配 \ 字符串,那么传递给 re.compile() 的字符串必须是"\\\\"。

由于字符串的转义,所以实际传递给 re.compile() 的是"\\",然后再通过正则表达式的转义,"\\" 会匹配到字符"\"。这样虽然可以正确匹配到字符 \,但是很麻烦,而且容易漏写反斜杠而导致 Bug。那么有什么好的解决方案呢?

原始字符串很好的解决了这个问题,通过在字符串前面添加一个r,表示原始字符串,不让字符串的反斜杠发生转义。那么就可以使用r"\\"来匹配字符\了。

3)pattern object 执行匹配

一旦你编译得到了一个 pattern object,你就可以使用 pattern object 的方法或属性进行匹配了,下面列举几个常用的方法,更多请看这里

regex.match(string[, pos[, endpos]])

  • 匹配从 pos 到 endpos 的字符子串的开头。匹配成功返回一个 match object,不匹配返回 None。
  • pos 的默认值是0,endpos 的默认值是 len(string),所以默认情况下是匹配整个字符串的开头。
  1. import re  
  2. pattern = re.compile("ar{1}")  
  3. print(pattern.match("army"))     # "ar"在开头,匹配成功  
  4. print(pattern.match("mary"))     # "ar"不在开头,匹配失败  
  5. print(pattern.match("mary"1))  # "ar"不在开头,但在子串的开头  
  6.   
  7. # 输出结果:  
  8. # <_sre.SRE_Match object; span=(0, 2), match='ar'>  
  9. # None  
  10. # <_sre.SRE_Match object; span=(1, 3), match='ar'>  

regex.search(string[, pos[, endpos]])

  • 扫描整个字符串,并返回它找到的第一个匹配(Match object)。
  • 和 regex.match() 一样,可以通过 pos 和 endpos 指定范围。
  1. pattern = re.compile("ar{1}")  
  2. match = pattern.search("mary")   # search  
  3. print(match)  
  4.   
  5. # 输出结果:  
  6. # <_sre.SRE_Match object; span=(1, 3), match='ar'>  

regex.findall(string[, pos[, endpos]])

  • 找到所有匹配的子串,并返回一个 list 。
  • 可选参数 pos 和 endpos 和上面一样。
  1. pattern = re.compile(r"\d+")  
  2. lst = pattern.findall("abc1def2rst3xyz")   # findall  
  3. print(lst)  
  4.   
  5. # 输出结果:  
  6. # ['1', '2', '3']  

regex.finditer(string[, pos[, endpos]])

  • 找到所有匹配的子串,并返回由这些匹配结果(match object)组成的迭代器。
  • 可选参数 pos 和 endpos 和上面一样。
  1. pattern = re.compile(r"\d+")  
  2. p = pattern.finditer("abc1def2rst3xyz")   
  3. for i in p:  
  4.     print(i)  
  5.   
  6. # 输出结果:  
  7. # <_sre.SRE_Match object; span=(3, 4), match='1'>  
  8. # <_sre.SRE_Match object; span=(7, 8), match='2'>  
  9. # <_sre.SRE_Match object; span=(11, 12), match='3'>  

4)match object 获取结果

在上面讲到,通过 pattern object 的方法(除 findall 外)进行匹配得到的返回结果都是 match object。每一个 match object 都包含了匹配到的相关信息,比如,起始位置、匹配到的子串。那么,我们如何从 match object 中提取这些信息呢?

match object 提供了一些方法,下面列举几个常用的方法,更多请看这里

match.group([group1, ...])

  • 返回 match object 中的字符串。
  • 每一个 ( ) 都是一个分组,分组编号从1开始,从左往右,每遇到一个左括号,分组编号+1。
  • 组 0 总是存在的,它就是整个表达式 。
  • 没有参数时,group1默认为0,这时返回整个匹配到的字符串。
  • 指定一个参数(整数)时,返回该分组匹配到的字符串。
  • 指定多个参数时,返回由那几个分组匹配到的字符串组成的 tuple。
  1. pattern = re.compile(r"(\w+) (\w+)")  
  2. m = pattern.match("Kobe Bryant, Lakers")  
  3. print(m)               # <_sre.SRE_Match object; span=(0, 11), match='Kobe Bryant'>  
  4. print(m.group())       # Kobe Bryant  
  5. print(m.group(1))      # Kobe  
  6. print(m.group(2))      # Bryant  
  7. print(m.group(12))   # ('Kobe', 'Bryant')  

match.groups()

  • 返回由所有分组匹配到的字符串组成的 tuple。
  1. >>> m = re.match(r"(\d+)\.(\d+)""24.1632")  
  2. >>> m.groups()  
  3. ('24''1632')  

match.start([group])

  • 没有参数时,返回匹配到的字符串的起始位置。
  • 指定参数(整数)时,返回该分组匹配到的字符串的起始位置。
  1. pattern = re.compile(r"(\w+) (\w+)")  
  2. m = pattern.match("Kobe Bryant, Lakers")  
  3. print(m.start())       # 0  
  4. print(m.start(2))      # 5  

match.end([group])

  • 没有参数时,返回匹配到的字符串的结束位置。
  • 指定参数(整数)时,返回该分组匹配到的字符串的结束位置。
  1. pattern = re.compile(r"(\w+) (\w+)")  
  2. m = pattern.match("Kobe Bryant, Lakers")  
  3. print(m.end())       # 11  
  4. print(m.end(1))      # 4  

match.span([group])

  • 返回一个二元 tuple 表示匹配到的字符串的范围,即 (start, end)。
  • 指定参数时,返回该分组匹配到的字符串的 (start, end)。
  1. pattern = re.compile(r"(\w+) (\w+)")  
  2. m = pattern.match("Kobe Bryant, Lakers")  
  3. print(m.span())     # (0, 11)  
  4. print(m.span(2))    # (5, 11)  

5)模块级别的函数

上面讲到的函数都是对象的方法,要使用它们必须先得到相应的对象。本节将介绍一些Module-Level Functions,比如 match(),search(),findall() 等等。你不需要创建一个 pattern object 就可以直接调用这些函数。

re.compile(pattern, flags=0):上面已经介绍过。

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

  1. pattern = re.compile(r"(\w+) (\w+)")  
  2. m = pattern.match("Kobe Bryant, Lakers")  
  3. # 相当于  
  4. m = re.match(r"(\w+) (\w+)","Kobe Bryant, Lakers")  
re.search(pattern, string, flags=0)
  1. pattern = re.compile(r"(\w+) (\w+)")  
  2. m = pattern.search("Kobe Bryant, Lakers")  
  3. # 相当于  
  4. m = re.search(r"(\w+) (\w+)","Kobe Bryant, Lakers")  

re.findall(pattern, string, flags=0):与上面类似。

re.finditer(pattern, string, flags=0):与上面类似。

6)编译标志(匹配模式)

在讲 re.compile() 函数时,曾说到该函数还接受可选的第二个参数,用以设置匹配模式。可选的匹配模式有:

  • re.IGNORECASE:忽略大小写,同 re.I

  • re.MULTILINE:多行模式,改变^和$的行为,同 re.M

  • re.DOTALL:点任意匹配模式,让'.'可以匹配包括'\n'在内的任意字符,同 re.S

  • re.LOCALE:使预定字符类 \w \W \b \B \s \S 取决于当前区域设定, 同 re.L

  • re.ASCII:使 \w \W \b \B \s \S 只匹配 ASCII 字符,而不是 Unicode 字符,同 re.A

  • re.VERBOSE:详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释。主要是为了让正则表达式更易读,同re.X。例如,以下两个正则表达式是等价的:

  1. a = re.compile(r"""\d +  # the integral part 
  2.                    \.    # the decimal point 
  3.                    \d *  # some fractional digits""", re.X)  
  4. b = re.compile(r"\d+\.\d*")  

三、修改字符串

第二部分讲的是字符串的匹配和搜索,但是并没有改变字符串。下面就讲一下可以改变字符串的操作。

1)分割字符串

split()函数在匹配的地方将字符串分割,并返回一个 list。同样的,re 模块提供了两种 split 函数,一个是 pattern object 的方法,一个是模块级的函数。

regex.split(string, maxsplit=0)

  • maxsplit用于指定最大分割次数,不指定将全部分割。
  1. pattern = re.compile(r"[A-Z]+")  
  2. m = pattern.split("abcDefgHijkLmnoPqrs")  
  3. print(m)  
  4.   
  5. # 输出结果:  
  6. # ['abc', 'efg', 'ijk', 'mno', 'qrs']  

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

  • 模块级函数,功能与 regex.split() 相同。
  • flags用于指定匹配模式。
  1. m = re.split(r"[A-Z]+","abcDefgHijkLmnoPqrs")  
  2. print(m)  
  3.   
  4. # 输出结果:  
  5. # ['abc', 'efg', 'ijk', 'mno', 'qrs']  

2)搜索与替换

另一个常用的功能是找到所有的匹配,并把它们用不同的字符串替换。re 模块提供了sub()subn()来实现替换的功能,而它们也分别有自己两个不同版本的函数。

regex.sub(repl, string, count=0)

  • 使用 repl 替换 string 中每一个匹配的子串,返回替换后的字符串。若找不到匹配,则返回原字符串。
  • repl 可以是一个字符串,也可以是一个函数。
  • 当repl是一个字符串时,任何在其中的反斜杠都会被处理。
  • 当repl是一个函数时,这个函数应当只接受一个参数(Match对象),并返回一个字符串用于替换。
  • count 用于指定最多替换次数,不指定时全部替换。
  1. def fun(m):  
  2.     return m.group().upper()  
  3.   
  4. pattern = re.compile(r"like", re.I)  
  5. s1 = pattern.sub(r"love""I like you, do you like me?")  
  6. s2 = pattern.sub(fun, "I like you, do you like me?")  
  7. print(s1)  
  8. print(s2)  
  9.   
  10. # 输出结果:  
  11. # I love you, do you love me?  
  12. # I LIKE you, do you LIKE me?  

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

  • 模块级函数,与 regex.sub() 函数功能相同。
  • flags 用于指定匹配模式。

regex.subn(repl, string, count=0)

  • 同 sub(),只不过返回值是一个二元 tuple,即(sub函数返回值, 替换次数)

re.subn(pattern, repl, string, count=0, flags=0)

模块级函数,功能同 regex.subn()。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值