使用正则表达式

给定一个正则表达式,可以用MATLAB和Python实现文本查找、替换和分割等任务。两门语言的用法有所不同。[大谦MATLAB,dqmatlab点com]

查找

正则表达式用相对比较复杂的规则匹配给定文本中的子字符串并进行提取。

【MATLAB】

在MATLAB中使用regexp函数和regexpi函数,可以用指定的正则表达式在给定文本中查找指定的子文本。regexp函数查找的时候对给定的文本有大小写区分,regexpi函数则没有大小写区分。

regexp函数的语法格式为:

startIndex=regexp(str,expression) 返回 str 中与正则表达式expression匹配的每个子字符串的起始位置。如果没有匹配项,则 startIndex 为空数组。

[startIndex,endIndex]=regexp(str,expression) 返回所有匹配项的起始位置和结束位置。

out=regexp(str,expression,outkey) 返回 outkey 指定的输出。例如,如果 outkey 为 'match',则 regexp 返回与该表达式匹配的子字符串而非其起始位置。

[out1,...,outN]=regexp(str,expression,outkey1,...,outkeyN) 按指定的顺序返回多个输出关键字指定的输出。例如,如果指定 'match', 'tokens',则 regexp 返回与expression匹配的子字符串以及与部分表达式匹配的标文。

___=regexp(___,option1,...,optionM) 使用指定的选项标记。例如,指定 'ignorecase' 时不区分大小写。

___=regexp(___,'forceCellOutput') 以元胞数组的形式返回每个输出结果。

regexp函数的outkey参数可取下面的值。

'start'(默认值)所有匹配项的起始位置,输出到startIndex

'end' 所有匹配项的结束位置,输出到endIndex

'tokenExtents' 所有标文的起始位置和结束位置

'match' 与expression匹配的每个子字符串的文本

'tokens' str中每个捕获的标文的文本

'names' 每个命名标文的名称和文本

'split' str的非匹配子字符串的文本

regexp函数的option参数可以取下面的值。

'all'或'once' 尽可能多地匹配表达式(默认值),或仅匹配一次

'nowarnings'或'warnings' 取消警告(默认值),或显示警告

'matchcase'或'ignorecase' 匹配字母大小写(默认值),或忽略大小写

'noemptymatch'或'emptymatch' 忽略零长度匹配项(默认值),或包括这些匹配项

'dotall'或'dotexceptnewline' 将点与任意字符匹配(默认值),或与除换行符 (\n) 之外的所有字符匹配

'stringanchors'或'lineanchors' 将^和$元字符应用于字符向量的开头和结尾(默认值),或应用于行开头和结尾。换行符(\n)指定行的结尾。行的开头指定为第一个字符,或紧跟在换行符后面的任何字符

'literalspacing'或'freespacing' 在匹配时包括空格字符和注释(默认值),或忽略它们。使用'freespacing',使用'\ '和'\#'匹配空白和#字符

下面结合实例介绍用正则表达式实现子文本的查找。现在还没有介绍正则表达式的编写,本例使用最简单的情况,即匹配固定字符串的情况,从给定字符串中查找“abc”。

在命令窗口输入:

code.matlab
>> a='abc123def456AbC';
>> [startIndex,endIndex]=regexp(a,'abc')
startIndex =
     1
endIndex =
     3

返回找到的子字符串的起始位置和终止位置,即给定字符串中的第1个字符到第3个字符。注意,默认时查找是有大小写区分的。

下面返回匹配的字符串。

code.matlab
>> out=regexp(a,'abc','match')
out =
  1×1 cell 数组
    {'abc'}

下面用“matchcase”选项指定查找时区分大小写,返回匹配字符串的起始位置。

code.matlab
>> out=regexp(a,'abc','matchcase')
out =
     1

下面用“ignorecase”选项指定查找时不区分大小写,返回匹配字符串的起始位置。

code.matlab
>> out=regexp(a,'abc','ignorecase')
out =
     1    13

返回两个数字,说明找到两个匹配字符串。

除了通过设置option参数来指定匹配规则,还可以使用搜索标志来实现相同的任务。MATLAB正则表达式能使用的搜索标志如表17-1所示。

表17-1 搜索标志设置

标记 说 明
(?-i) 匹配字母大小写(regexp 和 regexprep 的默认值)
(?i) 不匹配字母大小写(regexpi 的默认值)
(?s) 将模式中的点 (.) 与任意字符匹配(默认值)
(?-s) 将模式中的点与并非换行符的任意字符匹配
(?-m) 匹配文本开头和结尾的 ^ 和 $ 元字符(默认值)
(?m) 匹配行开头和结尾的 ^ 和 $ 元字符
(?-x) 在匹配时包括空格字符和注释(默认值)
(?x) 在匹配时忽略空格字符和注释。使用 '\ ' 和 '\#' 匹配空白和 # 字符

在命令行中输入:

code.matlab
>> out=regexp(a,'(?-i)abc')
out =
     1

该命令语句与下面的语句等价:

code.matlab
>> out=regexp(a,'abc','matchcase')

都返回区分大小写时匹配字符串的起始位置。

下面的语句:

code.matlab
>> out=regexp(a,'(?i)abc')
out =
     1    13

与语句

code.matlab
>> out=regexp(a,'abc','ignorecase')

等价,都返回不区分大小写时匹配字符串的起始位置。

【Python】

在Python中使用re模块实现正则表达式的应用。该模块提供了一系列函数,使用它们可以实现不同形式的文本查找、替换和分割等功能。

re模块提供了4个函数来实现不同形式的查找,即match, search, findall和finditer函数,前两个函数返回一个满足要求的匹配对象,后两个返回所有满足要求的匹配对象。使用re模块,首先要导入该模块:

code.matlab
>>> import re

re.match函数

re.match函数从给定文本打头的位置开始匹配,如果匹配不成功,返回None。该函数的语法格式为:

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

其中各参数的含义如表17-2中所示。

表17-2 re.match函数的参数

参 数 说 明
pattern 进行匹配的正则表达式
string 给定的文本
flags 标记,指定正则表达式的匹配方式如是否区分大小写等

flags参数用来指定正则表达式的匹配方式,其取值如表17-3中所示。如果同时设置多个标记,标记之间可以用竖线连接,如re.M|re.I。

表17-3 标记设置

标记 完整写法 说 明
re.I re.IGNORECASE 不区分大小写
re.M re.MULTILINE 支持多行
re.S re.DOTALL 使点做任意匹配,包括换行符在内的任意字符
re.L re.LOCALE 进行本地化识别匹配
re.U re.UNICODE 根据Unicode字符集解析字符
re.X re.VERBOSE 支持更灵活更详细的模式,比如多行、忽略空白、加入注释等

如果匹配成功,re.match函数返回一个Match对象,否则返回None。

下面给定一个字符串和一个匹配规则,用re.match函数进行匹配。

code.python
>>> import re
>>> a='abc123def456'
>>> m=re.match('abc',a)
>>> m
<re.Match object; span=(0, 3), match='abc'>

从字符串a的打头位置开始匹配'abc',匹配成功,返回一个Match对象,它的值为'abc',位置是第1个字符到第3个字符。

如果给定的字符串和匹配字符串有大小写区分,例如:

code.python
>>> b='aBC123dEf456'
>>> m=re.match('abc',b)
>>> m

返回的m为空,表示匹配不成功。如果不区分大小写,使用re.I标记。

code.python
>>> m2=re.match('abc',b,re.I)
>>> m2
<re.Match object; span=(0, 3), match=’Abc’>

现在匹配成功,返回匹配结果'Abc'。

re.search函数

跟re.match函数不同,re.search函数在整个给定的字符串中进行查找,并返回第一个匹配成功的对象。该函数的语法格式为:

code.python
re.search(pattern, string, flags=0)

函数各参数的说明与re.match函数的相同,请参阅。

下面给定一个字符串,在整个字符串中查找'def',不区分大小写,返回查找到的第1个结果。

code.python
>>> import re
>>> a='aBC123dEf456'
>>> m=re.search('def',a,re.I)
>>> m
<re.Match object; span=(6, 9), match='dEf'>

匹配成功,返回匹配结果'dEf'。

re.findall函数

re.findall函数在给定字符串中查找正则表达式所匹配的所有子字符串,并将结果以列表的形式返回,如果匹配不成功,返回空列表。

注意:re.match和re.search函数只匹配一次,re.findall函数则找出所有匹配结果。

re.findall函数的语法格式为:

code.python
findall(pattern, string,flags=0)

其中,各参数的意义与re.match函数的相同,请参阅。

下面给定一个字符串,在整个字符串中查找'abc',不区分大小写,返回查找到的所有结果。

code.python
>>> import re
>>> a='aBC123dEf456abc789abC'
>>> m=re.findall('abc',a,re.I)
>>> m
['aBC', 'abc', 'abC']

可见,匹配成功的结果用列表的形式给出。

re.finditer函数

跟re.findall函数一样,re.finditer函数也是在给定字符串中找到正则表达式所匹配的所有子字符串。不同的是,前者将匹配结果以列表的形式给出,后者把匹配结果以迭代器的形式返回。该函数的语法格式为:

code.python
re.finditer(pattern, string, flags=0)

其中,各参数的意义与re.match函数的相同,请参阅。

下面给定一个字符串,在整个字符串中查找'abc',不区分大小写,返回查找到的所有结果。

code.python
>>> import re
>>> a='aBC123dEf456abc789abC'
>>> m=re.finditer('abc',a,re.I)
>>> m
<callable_iterator object at 0x0000000005BF0F48>

可见,re.finditer函数是将匹配结果以迭代器的形式返回的。使用for循环可以输出迭代器中的对象。

code.python
>>> for i in m:
		print(i)
<re.Match object; span=(0, 3), match='aBC'>
<re.Match object; span=(12, 15), match='abc'>
<re.Match object; span=(18, 21), match='abC'>

可见,迭代器m中有3个匹配对象,for循环输出了它们的值和在给定字符串中的位置。

替换

替换是在查找到指定子字符串后用给定的字符串替换它。

【MATLAB】

在MATLAB中用正则表达式替换文本,使用regexprep函数。该函数的语法格式为:

newStr=regexprep(str,expression,replace) 将 str 中与 expression 匹配的文本替换为 replace 描述的文本。更新的文本返回到newStr变量。

newStr=regexprep(str,expression,replace,option1,...optionM) 使用指定的选项进行查找。例如,指定 'ignorecase' 时不区分大小写。

在命令窗口输入:

code.matlab
>> a='abc123def456AbC';
>> newStr=regexprep(a,'abc','')
newStr =
    '123def456AbC'

在给定字符串中删除了子字符串“abc”。注意,默认时区分大小写。

【Python】

所谓替换,是要在查找的基础上,用给定的对象替换匹配到的对象。使用re.sub和re.subn函数进行替换。

re.sub函数

函数的语法格式为:

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

其中各参数的意义为:

pattern - 进行匹配的正则表达式。

repl - 用作替换的字符串,可以是一个函数。

string – 给定的原始字符串。

count – 进行替换的最大次数,默认0表示全部替换。

flags - 指定正则表达式匹配方式的标记。

下面给定一个字符串,在整个字符串中查找'abc',不区分大小写,匹配结果全部替换为'xyz'。

code.python
>>> import re
>>> a='aBC123dEf456abc789abC'
>>> m=re.sub('abc','xyz',a,0,re.I)
>>> m
'xyz123dEf456xyz789xyz'

可见,所有匹配结果都被替换为'xyz'。

re.subn函数

re.subn函数的作用与re.sub函数的相同,只是该函数的返回值是一个元组,元组有两个值,第一个值为实现替换后的字符串,第二个值为进行替换的次数。

该函数的语法格式为:

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

其中各参数的意义与re.sub函数的相同,请参阅。

下面给定一个字符串,在整个字符串中查找'abc',不区分大小写,匹配结果全部替换为'xyz',使用re.subn函数。

code.python
>>> import re
>>> a='aBC123dEf456abc789abC'
>>> m=re.subn('abc','xyz',a,0,re.I)
>>> m
('xyz123dEf456xyz789xyz', 3)

试比较它与re.sub函数的返回值。

分割

对给定字符串进行分割,需要指定分隔符,分割后的内容就是不匹配分隔符的部分。使用正则表达式进行分割,是将匹配正则表达式的字符串作为分隔符来使用,将不匹配的部分以数组形式返回。

【MATLAB】

MATLAB中用正则表达式实现文本分割,在使用regexp函数时设置outkey参数的值为“split”。

下面给定字符串,将字符串中的“a”作为分隔符进行分割。

code.matlab
>> a='aBC&123dEf&456abc&789abC';
>> splitStr=regexp(a,'a','split')
splitStr =
  1×4 cell 数组
    {0×0 char}    {'BC&123dEf&456'}    {'bc&789'}    {'bC'}

结果以元胞数组的形式返回。

稍微复杂点的情况,将给定字符串中的数字作为分隔符进行分割。

code.matlab
>> splitStr=regexp(a,'\d+','split')
splitStr =
  1×4 cell 数组
    {'aBC&'}    {'dEf&'}    {'abc&'}    {'abC'}

正则表达式“\d+”表示1个以上的数字,匹配给定字符串中的“123”、“456”和“789”。将它们作为分隔符,剩下的部分以元胞数组的形式返回。

【Python】

re.split函数将能够匹配到的子字符串作为分隔符分割原始字符串,将分割后的结果以列表形式返回。该函数的语法格式为:

code.python
re.split(pattern, string[, maxsplit=0, flags=0])

其中各参数的意义为:

pattern - 进行匹配的正则表达式。

string – 给定的原始字符串。

maxsplit – 最大分割次数,默认值为0,表示不限次数。

flags - 指定正则表达式匹配方式的标记。

下面给定一个字符串,在整个字符串中查找'&',找到后用作分隔符对原始字符串进行分割,返回分割的结果。

code.python
>>> import re
>>> a='aBC&123dEf&456abc&789abC'
>>> m=re.split('&',a)
>>> m
['aBC', '123dEf', '456abc', '789abC']

可见,'&'找到后被用作分隔符。以列表形式返回分割后的结果。

如果只分割2次,设置maxsplit参数的值为2。

code.python
>>> m=re.split('&',a,2)
>>> m
['aBC', '123dEf', '456abc&789abC']

如果没有匹配结果,则返回原始字符串。

code.python
>>> m=re.split('%',a)
>>> m
['aBC&123dEf&456abc&789abC']