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,  }。例 <img src="\w+\.gif"> 与 <img> HTML 标记匹配(当文件名包含一个或多个字符时)。

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

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

expr{n,  }    与expr匹配的元素至少出现n次。 例 <a href="\w{1,}\.html">'与 <a> HTML 标记匹配(当文件名包含一个或多个字符时)。

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

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

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

s='<tr valign=top><td><a name="19184"></a>xyz';

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

输出:

{'<tr valign=top><td><a name="19184"></a>'}

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

s='<tr valign=top><td><a name="19184"></a>xyz';

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

输出:

{'<tr valign=top>'}    {'<td>'}    {'<a name="19184">'}    {'</a>'}

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

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

expr q    积极表达式:与尽可能多的字符匹配。如给定文本 <tr><td><p>text</p></td>,表达式 </?t.*> 匹配介于 <tr 和 /td> 之间的所有字符。

expr q?    消极表达式:与所需的尽可能少的字符匹配。如文本 <tr><td><p>text</p></td>,表达式 </?t.*?> 在第一次出现右尖括号 (>) 时结束每个匹配项:{'<tr>'}    {'<td>'}    {'</td>'}。

expr q+    主动表达式:最大程度地匹配,但不重新扫描文本的任何部分。如给定文本 <tr><td><p>text</p></td>,表达式 </?t.*+>不返回任何匹配项,这是因为右尖括号是使用 .* 捕获的且不进行重新扫描。

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

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

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

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

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

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

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

\<expr    匹配以expr开头的英文单词。如 \<n\w* 与以 n 开头的任何单词匹配。

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等价于 \<expr。

(?<!test)expr    负向后发断言:向后查找与 test 不匹配的字符。即匹配前面的字符没有test的字符。如 (?<!\d)(\d)(?!\d) 与一位数字匹配(不紧随其他数字前后的数字)。

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

s='<a href="www.baidu.com">';

regexp(s,'(?<=<a href=").*?(?=">)','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+).*>.*</\1> 从文本 <title>Some text</title> 捕获 HTML 标记的标文,例如 title。

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

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

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

(?(name)expr1|expr2)    若存在名为name的标记,则匹配expr1,否则匹配expr2。如 Mr(?<sex>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>获取名为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?$','\<le\w+?','\w+er\>?','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.

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,869评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,716评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,223评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,047评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,089评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,839评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,516评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,410评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,920评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,052评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,179评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,868评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,522评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,070评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,186评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,487评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,162评论 2 356

推荐阅读更多精彩内容