Skip to main content
 首页 » 编程设计

Python正则表达式入门

2022年07月19日206davidwang456

Python正则表达式入门

正则表达式是一种语法,或者说是从较大文本中搜索、提取和操作特定字符串模式的语言。广泛应用于涉及文本验证、NLP和文本挖掘的项目中。

几乎每种语言都有相应实现,Python实现是标准模块re。本文通过一些实例介绍其基本语法。

正则表达式模式

正则表达式模式是用于表示一般性文本、数字或符号的特定语言,因此可用来提取符合这种模式的文本。

一个简单示例表达式为:‘\s+’.
这里的\s表示匹配任何空白字符,+号表示至少1个或多个空白字符。因此在模式也会匹配\t字符。

下面代码编译一个正在表达式:

import re    
regex = re.compile('\s+') 

首先导入re模块,然后定义匹配至少一个空白字符的表达式。

通过正则表达式分隔字符串

假设有下面一个字符串存储课程编号、编码和名称:

text = """101 COM    Computers 
205 MAT   Mathematics 
189 ENG   English"""  

共三条记录,但单词之间的空格数不等。我们需要分隔这三条记录至多个数字和单词,下面提供两种方法实现。

import re    
regex = re.compile('\s+') 
 
# 1. re.split('\s+', text) 
re.split('\s+', text) 
 
# 2. 使用 regex.split(text) 
regex.split(text) 
 
#> ['101', 'COM', 'Computers', '205', 'MAT', 'Mathematics', '189', 'ENG', 'English'] 

上面两种方式那种更有效拟?如果多次使用一个特定模式,最好不要每次都调用re.split方法,导致正则表达式编译多次。

findall,search,match

下面我们需要抽取所有课程编号,也就是从文本中抽取101,205,189。

使用 re.findall()方法

regex_num = re.compile('\d+') 
regex_num.findall(text) 
 
#> ['101', '205', '189'] 

代码中\d表示匹配任何数字,+号表示至少有一个数字。如果是*号表示0个或多个数字。最后findall方法抽取所有符合条件的数字作为list返回。

re.search() vs re.match()

regex.search()用于在文本中搜索模式,但不想findall返回list,而是返回特定的匹配对象,其包括第一次模式匹配的开始位置和结束位置。

而regex.match()也返回匹配对象,但它要求模式出现在文本的开头。 请看示例代码:

import re 
 
string_with_newlines = """something 
someotherthing""" 
 
 
print re.match('some', string_with_newlines) # matches 
print re.match('someother', string_with_newlines) # won't match 
print re.match('^someother', string_with_newlines, re.MULTILINE) # also won't match 
print re.search('someother', string_with_newlines) # finds something 
print re.search('^someother', string_with_newlines,  re.MULTILINE) # also finds something 
 
m = re.compile('thing$', re.MULTILINE) 
 
print m.match(string_with_newlines) # no match 
print m.match(string_with_newlines, pos=4) # matches 
print m.search(string_with_newlines,  re.MULTILINE) # also matches 

替换文本

替换文本使用regex.sub()方法。这里我们text中的每个课程代码后面有tab字符。

# define the text 
text = """101   COM \t  Computers 
205   MAT \t  Mathematics 
189   ENG  \t  English"""   
print(text) 
#> 101   COM    Computers 
#> 205   MAT     Mathematics 
#> 189   ENG     English 

我们需要去掉所有多余的空格,并在一行显示所有记录。这里使用regex.sub方法替换\s模式为单个空格。

# replace one or more spaces with single space 
regex = re.compile('\s+') 
print(regex.sub(' ', text)) 
# or 
print(re.sub('\s+', ' ', text)) 
#> 101 COM Computers 205 MAT Mathematics 189 ENG English 

如果仅想去掉额外的空格并保留换行符,需要表达式排除换行符并包括所有其他空白符。这可以通过使用负向前瞻(?!\n)来实现。它检查即将到来的换行字符并将其从模式中排除。

# get rid of all extra spaces except newline 
 
regex = re.compile('((?!\n)\s+)') 
print(regex.sub(' ', text)) 
 
#> 101 COM Computers 
#> 205 MAT Mathematics 
#> 189 ENG English 

分组

正则分组是非常有用的特性,可以将所需的匹配对象提取为单独的项。假如需要抽取课程编号、编码、名称作为单独项,如果不使用分组:

text = """101   COM   Computers 
205   MAT   Mathematics 
189   ENG    English"""   
 
# 1. extract all course numbers 
re.findall('[0-9]+', text) 
 
# 2. extract all course codes 
re.findall('[A-Z]{3}', text) 
 
# 3. extract all course names 
re.findall('[A-Za-z]{4,}', text) 
 
#> ['101', '205', '189'] 
#> ['COM', 'MAT', 'ENG'] 
#> ['Computers', 'Mathematics', 'English'] 

我们使用了三个独立正则表达式实现,但有更好的方式,正则分组。因为记录模式相同,我们可以为所有记录构建统一模式,并把需要抽取的内容放在分组中,使用().

# define the course text pattern groups and extract 
 
course_pattern = '([0-9]+)\s*([A-Z]{3})\s*([A-Za-z]{4,})' 
re.findall(course_pattern, text) 
 
#> [('101', 'COM', 'Computers'), ('205', 'MAT', 'Mathematics'), ('189', 'ENG', 'English')] 

注意,num: [0-9]+、code: [A-Z]{3}和name: [A-Za-z]{4,} 模式都放在括号()中以形成组。

贪婪匹配

正则表示缺省匹配是贪婪匹配,即尝试匹配尽可能多的内容。下面是一段html内容,我们需要返回html标记。

text = "< body>Regex Greedy Matching Example < /body>" 
re.findall('<.*>', text) 
#> ['< body>Regex Greedy Matching Example < /body>'] 

结果提取了整个字符串,而不是匹配到’ > '的第一次出现,我本来希望出现在第一个body标签的末尾。这是regex默认的贪婪或“全盘接收”行为。

相反方式是懒匹配,即尽可能小方式匹配。在模式的结尾增加?表示:

re.findall('<.*?>', text) 
#> ['< body>', '< /body>'] 

如果仅需要第一个匹配结果,则使用search代替:

re.search('<.*?>', text).group() 
#> '< body>' 

总结

本文简要介绍了Python正则表达式,注意介绍了模式及其常用方法,同时也通过示例说明了懒匹配和分组匹配。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/102325583