Python正则表达式入门

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正则表达式,注意介绍了模式及其常用方法,同时也通过示例说明了懒匹配和分组匹配。

你可能感兴趣的:(python)