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的位置
matchexpression 中的模式匹配的每个子字符串的文本
tokensstr 中每个捕获的标文的文本,即表达式中标记(tokens)的字串
names为匹配到的命名标记的标记名
splitstr 的非匹配子字符串的文本

用法3:

[out1, ..., outN] = regexp(str, expression, outkey1, ..., outkeyN) 按指定的顺序返回多个输出关键字指定的输出。例如,如果指定 matchtokens,则 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'rainpain.ain'匹配。

  • [^] 匹配除括号内字符的其它任意字符。例[^*rp]ain 与以 ain结尾的所有由四个字母组成的序列(rainpain'*ain 除外)匹配。如,它与 gainlainvain匹配。

  • [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} 匹配 mmmmm

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

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

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

  • expr+expr匹配的元素出现1更多次,相当于{1, }。例 <img src="\w+\.gif"> 与 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">'与 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. 中的 Flyfall。特殊情况:expr(?=$)等价于expr$expr(?=\>) 等价于 expr\>

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

  • (?<=test)expr 后发断言:向后查找与 test 匹配的字符。即匹配前面的字符有test的字符。如 (?<=re)\w* 匹配紧跟 re 的词汇,例如输入文本 renew, reuse, recycle 中的 newusecycle。特殊情况:(?<=^)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 同时与 testexpr 匹配。如 (?=[a-z])[^aeiou] 与辅音匹配。
  • (?!test)expr 匹配 expr,但不匹配 test。如 (?![aeiou])[a-z] 与辅音匹配。

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

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

条件运算法:

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

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

  • (?(cond)expr1 | expr2) 如果条件 condtrue,则匹配 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 开头时)。
  • (?expr) 匹配 expr并创建命名为name的标记。 (?<month>\d+)-(?<day>\d+)-(?<yr>\d+)mm-dd-yy 形式的输入日期中创建命名月、日和年标记。
  • \k 匹配名为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 将捕获 5XXXXX 的标文。
  • (??@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)匹配字母大小写(regexpregexprep 的默认值)。
(?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.

本文首发于 微信公众号:清贫王子
在这里插入图片描述

  • 7
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值