Matlab 正则表达式

使用Matlab处理字符串及文本时,需要与正则表达式打交道。正则表达式是一个非常重要的编程概念,主流的编程语言都对正则表达式进行了很好的支持,Matlab也不例外。

本期推文就让我们来总结一下Matlab提供的正则表达式吧!

1 引言

正则表达式(Regular Expression),又称规则表达式,本质上是一串字符,它定义了某种字符串模式,通常被用来检索、替换那些符合某个模式(规则)的文本。

Matlab 提供的正则表达式库函数主要有三个:

(1) regexp---用于对字符串进行查找,大小写敏感;

(2) regexpi---用于对字符串进行查找,大小写不敏感;

(3) regexprep---用于对字符串进行查找并替换。

下面主要介绍一下 regexp 这个函数的主要用法:

用法1:

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

用法2:

out = regexp(str, expression, outkey) 返回 outkey 指定的输出。例如,如果 outkey 为 'match',则 regexp 返回与该表达式匹配的子字符串而非其开始索引。outkey通常的取值有:

输出关键字返回

start 默认值所有匹配项的开始,startIndex

end所有匹配项的结束,endIndex

tokenExtents所有表文的开始和结束索引,和tokens一起用,指示出现tokens的位置

match与 expression 中的模式匹配的每个子字符串的文本

tokensstr 中每个捕获的标文的文本,即表达式中标记(tokens)的字串

names为匹配到的命名标记的标记名

splitstr 的非匹配子字符串的文本

用法3:

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

用法4:

___ = regexp(___, option1, ..., optionM)使用指定的选项标志修改搜索。例如,指定 'ignorecase' 以执行不区分大小写的匹配。可以包括任何输入并请求之前语法中的任何输出。

option - 搜索选项覆盖说明

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

nowarningswarnings取消警告(默认值),或显示警告。

matchcaseignocase匹配字母大小写(默认值),或忽略大小写。

noemptymatchemptymatch忽略零长度匹配项(默认值),或包括这些匹配项。

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

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

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

用法5:

___ = regexp(___, 'forceCellOutput')以标量元胞的形式返回每个输出参数。元胞包含被描述为上述语法输出的数值数组或子字符串。可以包括任何输入并请求之前语法中的任何输出。

2 单个字符匹配

正则表达式,指定为字符向量、字符向量元胞数组或字符串数组。

每个表达式可包含字符、元字符、运算符、标文和用于指定在 str 中匹配的模式的标志。

2.1 元字符

元字符表示字母、字母范围、数字和空格字符。使用它们来构造广义的字符模式。

.  匹配任何单个字符,包括空格和换行符。例..ain 与以 ain 结尾的五个连续字符序列匹配。

[]    匹配括号内的任意字符,$, |, ., *, +, ?, -这些字符按字面匹配。例[rp.]ain'与 rain、pain 或 .ain'匹配。

[^]  匹配除括号内字符的其它任意字符。例[^*rp]ain 与以 ain结尾的所有由四个字母组成的序列(rain、pain'和 *ain 除外)匹配。如,它与 gain、lain 或 vain匹配。

[a-b]    匹配a-b范围中的任意字符,如[a-z], A-Z, [0-9], A-y, [10-99]。

\w    匹配任意英文字母、数字、下划线,等价于 [a-z_A-Z0-9]或 [a-zA-Z_0-9]。例 \w*标识一个单词。

\W    匹配任意非英文字母、数字、下划线,等价于 [^a-zA-Z_0-9]。例 \W*标识非单词项。

\s    匹配任意非空白(空格)字符,等价于 [\f\n\r\t\v]。 如 \w*n\s 与以字母 n 结尾且后跟空白字符的单词匹配。

注: 字符表示

运算符

\a警报(蜂鸣)

\b退格符

\f换页符

\n换行符

\r回车符

\t水平制表符

\v垂直制表符

\S    匹配任意非空白字符,等价于 [^ \f\n\r\t\v]。例 \d\S 与数字(后跟任意非空白字符)匹配。

\d    匹配任意数字,等价于 [0-9]。例 \d* 与任意数量的连续数字匹配。

\D    匹配任意非数字,等价于 [^0-9]。例 \w*\D\> 与不以数字结尾的单词匹配。

oN或\o{N}    匹配八进制数N对应的Unicode字符。例 \o{40} 与八进制 40 定义的空格字符匹配。

xN或\x{N}    匹配十六进制数N对应的Unicode字符。例 \x2C 与十六进制 2C 定义的逗号字符匹配,[\x4e00-\x9fa5] 匹配任意汉字。

2.2 特殊字符

\char    匹配表达式中的特殊字符,进行转义。$,^,*,(,),+,=,{,},<,>,|,.,\,?, -。这些特殊字符前边加上 \ 将会对其转义,使得匹配他们的字面值。

3 字符串匹配

3.1 多次匹配

元字符及其特殊字符的匹配,每次只能匹配一个字符,如果需要匹配多个字符,即字符串的匹配,那么就要重复好几次元字符的表达式。

比如,匹配 mmm,那么就可以用正则表达式 mmm, 但还有一种更简单的表示法 m{3}。其中 {}表示匹配前面的表达式出现的次数,称为限定符,m{2, 3} 匹配 mm 和 mmm。

除了 {} 限定符,还有其他常用的一些限定符,描述如下:

expr*    与expr匹配的元素出现0或更多次,相当于{0,  }。例 \w*与任意长度的单词匹配。

expr?  与expr匹配的元素出现0或1次,相当于{0,  1}。例 \w*(\.m)? 与单词或以扩展名 .m 结尾(此条件为可选条件)的单词匹配。

expr+    与expr匹配的元素出现1或更多次,相当于{1,  }。例 HTML 标记匹配(当文件名包含一个或多个字符时)。

expr{n}    与expr匹配的元素出现n次,相当于{n, n}。 例 \d{4} 与四个连续数字匹配。

expr{n, m}    与expr匹配的元素至少出现n次但不多于m次 。例 \S{4,8} 与四到八个非空白字符匹配。

expr{n,  }    与expr匹配的元素至少出现n次。 例 '与 HTML 标记匹配(当文件名包含一个或多个字符时)。

假设我们要在文本中搜索美国的社会安全号码,号码的格式是 000-00-0000,那么匹配它的正则表达式可以写为 \d{3}\-\d{2}\-\d{4}。 注意到 - 是特殊字符,所以用 \- 进行了转义。

如果希望字符号码连续出现,如000000000,也可以不出现,即 000-00-0000。上面两种形式都属于正确的格式,这时可以在字符 - 后面加上数量限定符 ? ,因此表达式可改写为 \d{3}\-?\d{2}\-?\d{4}\-?。

另外,当我们使用 expr*时,Matlab 将尽可能的匹配最长的字符字串,如

s='xyz';

regexp(s,'<.*>','match')

输出:

{''}

如果我们希望匹配尽可能短的字符字串时,可以在上面使用的表达式后加个 ?, 即 .*?,如

s='xyz';

regexp(s,'<.*?>','match')

输出:

{''}    {''}    {''}    {''}

上面的例子说明了对限定符的一种显示模式之一。

下面具体说明限定符的三种模式——限定修饰符,简单起见,用 q 表示上述6个限定符中的任意一个。

expr q    积极表达式:与尽可能多的字符匹配。如给定文本

text

,表达式 匹配介于 之间的所有字符。

expr q?    消极表达式:与所需的尽可能少的字符匹配。如文本

text

,表达式 在第一次出现右尖括号 (>) 时结束每个匹配项:{''}    {''}    {''}。

expr q+    主动表达式:最大程度地匹配,但不重新扫描文本的任何部分。如给定文本

text

,表达式 不返回任何匹配项,这是因为右尖括号是使用 .* 捕获的且不进行重新扫描。

3.2 零宽断言/环顾断言(左顾右盼)——利用上下文匹配

利用上下文匹配可以说非常常用,比如想要提取一段文本中特定的部分内容,那么零宽断言就非常适合干这类事情。

零宽断言查找紧邻预期匹配项前后但并非该匹配项一部分的模式。

指针停留在当前位置,并且将放弃或不捕获对应于 test 表达式的字符。因此,前向断言可匹配重叠字符组。

在介绍零宽断言之前,先介绍下定位点。表达式中的定位点与文本或单词的开头或结尾匹配。

^expr    匹配以expr开头的字符串。如 ^M\w* 与以 M 作为文本开头的单词匹配。

expr$    匹配以expr结尾的字符串。如 '\w*m$ ' 与以 m 作为文本结尾的单词匹配。

\

expr\>    匹配以expr结尾的英文单词。如 \w*e\> 与以 e 结尾的任何单词匹配。

回过头来,下面我们介绍零宽断言

expr(?=test)    先行断言:向前查找与test匹配的字符。即匹配后面跟的字符是test的字符。如 \w*(?=ing) 匹配后跟 ing 的词汇,匹配输入文本 Flying, not falling. 中的 Fly和 fall。特殊情况:expr(?=$)等价于expr$和 expr(?=\>) 等价于 expr\>。

expr(?!test)    负向先行断言:向前查找与test不匹配的字符。即匹配后面跟的字符不是test的字符。如 i(?!ng) 匹配字母 i 的后面不跟 ng 的字符。

(?<=test)expr    后发断言:向后查找与 test 匹配的字符。即匹配前面的字符有test的字符。如 (?<=re)\w* 匹配紧跟 re 的词汇,例如输入文本 renew, reuse, recycle 中的 new、use和 cycle。特殊情况:(?<=^)expr等价于 ^expr和 (?<=\<)expr等价于 \

(?

实际应用中,可以通过组合上面4中断言进行文本内容的提取,比如我们想要提取'' 文本中的网址,那么可以同时使用先行和后发断言,“左顾右盼”来提取网址内容:

s='';

regexp(s,'(?<=)','match')

输出:

{'www.baidu.com'}。

3.3 逻辑条件匹配

如果我们在表达式之前指定先行断言,即(?=test)expr等,则运算等同于逻辑 AND。这一点比较容易混淆。

(?=test)expr    同时与 test 和 expr 匹配。如 (?=[a-z])[^aeiou] 与辅音匹配。

(?!test)expr    匹配 expr,但不匹配 test。如 (?![aeiou])[a-z] 与辅音匹配。

逻辑和条件运算符允许我们测试给定条件的状态,然后使用结果确定哪个模式(如果有)与下一条件匹配。这些运算符支持逻辑 OR、if 或 if/else 条件。

条件可以是标文、环顾运算符或 (?@cmd) 形式的动态表达式。动态表达式必须返回逻辑值或数值。

条件运算法:

expr1 | expr2   匹配表达式 expr1 或表达式 expr2。比如 (let|tel)\w+ 匹配以 let 或 tel 开头的单词。

(?(cond)expr)    如果条件 cond 为 true,则匹配 expr。如 (?(?@ispc)[A-Z]:\\) 匹配驱动器名称,例如 C:\(在 Windows® 系统上运行时)。

(?(cond)expr1 | expr2)    如果条件 cond 为 true,则匹配 expr1。否则,匹配 expr2。如 Mr(s?)\..*?(?(1)her|his) \w* 匹配包含 her 的文本(当文本以 Mrs 开头时),或包含 his 的文本(当文本以 Mr 开头时)。

4 标记(tokens)匹配

标记这部分是较难的一部分,但是使用得当可以实现非常强大的功能。

任何的正则表达式都可以用圆括号括起来作为一个标记。可以按标记在文本中的顺序引用该标记(顺序标记),或将名称分配给标记以便于代码维护和使输出更易于阅读。

(expr)    匹配expr并创建标记。如 Joh?n\s(\w*) 捕获一个标记,该标记包含名字为 John 或 Jon 的任何人的姓氏。

(?:expr)    匹配expr,不创建标记。

(?>expr)    匹配expr,不创建标记,不回溯扫描。

(expr1|expr2)    匹配expr1或者expr2,创建标记。

\N    匹配第N个标记,N从1开始。如 <(\w+).*>.* 从文本 Some text 捕获 HTML 标记的标文,例如 title。

(?(N)expr1|expr2)    如果找到第 N 个标文,则匹配 expr1。否则,匹配 expr2。如 Mr(s?)\..*?(?(1)her|his) \w*匹配包含 her 的文本(当文本以 Mrs开头时),或包含 his的文本(当文本以 Mr 开头时)。

(?expr)    匹配 expr并创建命名为name的标记。 (?\d+)-(?\d+)-(?\d+) 在 mm-dd-yy 形式的输入日期中创建命名月、日和年标记。

\k    匹配名为name的标记。<(?\w+).*>.*>从文本 Some text 捕获 HTML 标记的标文,例如 title。

(?(name)expr1|expr2)    若存在名为name的标记,则匹配expr1,否则匹配expr2。如 Mr(?s?)\..*?(?(sex)her|his) \w* 匹配包含 her 的文本(当文本以 Mrs 开头时),或包含 his 的文本(当文本以 Mr 开头时)。

5 动态正则表达式

动态表达式允许我们执行 MATLAB 命令或正则表达式以确定要匹配的文本。

将动态表达式括起来的括号创建捕获组。

(??expr)    解析 expr 并将得到的项包括在匹配表达式中。解析后,expr 必须对应于完整的有效正则表达式。使用反斜杠转义字符 (\) 的动态表达式需要两个反斜杠:一个用于 expr 的初始解析,一个用于完整匹配。如 ^(\d+)((??\\w{$1})) 通过读取匹配项开头的数字确定匹配的字符数。(\w,\W,\d,\D,\s,\S,和\char这些在动态表达式中需要再加个\)。动态表达式括在另一组括号中,以便在标记中捕获生成的匹配项。例如,匹配 5XXXXX 将捕获 5 和 XXXXX 的标文。

(??@cmd)     执行 cmd 表示的 MATLAB 命令,并将该命令返回的输出包括在匹配表达式中。(.{2,}).?(??@fliplr($1)) 查找长度至少为四个字符的回文,例如 abba。

(?@cmd)     执行 cmd 表示的 MATLAB 命令,但放弃该命令返回的任何输出。(对诊断正则表达式有帮助。)\w*?(\w)(?@disp($1))\1\w* 匹配包括双字母(例如 pp)的单词并显示中间结果。

在动态表达式中,使用下列运算符定义替代文本。

替代运算符

$&或$0当前作为匹配项的输入文本部分,即获取匹配成功的字串。

$`获取匹配成功的字符串前面部分

$'紧随当前匹配项的输入文本部分(使用 $''表示$')

$N获取第N个标记

$获取名为name的标记

${cmd}在 MATLAB 执行命令 cmd 时返回的输出

注释:

(?#comment)     在正则表达式中插入注释。匹配输入时将忽略注释文本。如 (?# Initial digit)\<\d\w+ 包括一个注释,并匹配以一个数字开头的单词。

6 搜索标志

搜索标志修改匹配表达式的行为。在表达式中使用搜索标志的替代方法是传递 option 输入参数。

标志说明

(?-i)匹配字母大小写(regexp 和 regexprep 的默认值)。

(?i)不匹配字母大小写(regexpi 的默认值)。

(?s)将模式中的点 (.) 与任意字符匹配(默认值)。

(?-s)将模式中的点与并非换行符的任意字符匹配。

(?-m)匹配文本开头和结尾的 ^ 和 $ 元字符(默认值)。

(?m)匹配行开头和结尾的 ^ 和 $ 元字符。

(?-x)在匹配时包括空格字符和注释(默认值)。

(?x)在匹配时忽略空格字符和注释。使用 `\ ' 和 '#' 匹配空格和 # 字符。

该标志修改的表达式可显示在括号后,例如

(?i)\w*

或显示在括号内并使用冒号 (:) 与该标志分隔开,例如

(?i:\w*)

7 多行字符串与多正则表达式

7.1 多字符串与单个正则表达式匹配

多个字符串存在一个元胞数组里之后,每一个字符串与正则表达式匹配,返回值的维数与元胞数组的维数相同。

s= {'letter';'tell';'lethal';'television';'other'};

regexp(s,'(let|tel)\w+','match')

输出:


5x1的cell。

7.2 多个字符串与多个正则表达式匹配

这种情况下,应该满足字符串元胞数组中字符串的个数和正则表达式的个数相等,但维数不一定要相等。

如可以用 5x1的元胞数组与1x4的正则表达式相匹配。

s= {'letter';'tell';'lethal';'television';'other'};

expr= {'^t\w+?','\w+r?$','\?','l.*r?'};

regexp(s,expr,'match')

7.3 多字符串的替换

这个功能是在匹配的基础上,在表达式后面加入要替换的字符串即可。

s= {'letter';'tell';'lethal';'television';'other'};

s1=regexprep(s,'(.)\1','**','ignorecase');

输出:


8 结语

使用正则表达式的过程中,如果是每天与它打交道,也就很容易记住这些规则,孰能生巧,然而长时间不使用正则表达式,就会渐渐的生疏。

因此推文总结了正则表达式常用的用法和一些相关示例说明,没事干的时候就刷一刷,帮助记忆、理解。同时,希望能够帮助有相同需要的朋友。

参考文献

匹配正则表达式(区分大小写) - MATLAB regexp - MathWorks 中国

Matlab的正则表达式:字符串及文本处理的利器(上)

Matlab的正则表达式:字符串及文本处理的利器(下)

Luo H . MATLAB GUI设计学习手记 (第3版)[J]. 2014.

你可能感兴趣的:(Matlab 正则表达式)