Main Content

正则表达式

本主题说明什么是正则表达式以及如何使用它们来搜索文本。正则表达式灵活而强大,尽管它们使用复杂的语法。正则表达式的一种替代选择是pattern(自 R2020b 开始提供),它更易于定义,并且生成的代码更易于阅读。有关详细信息,请参阅构建模式表达式

什么是正则表达式?

正则表达式是一串用于定义某种模式的字符。在有些情况下(例如,在解析程序输入或处理文本块时),您通常会使用正则表达式在文本中搜索与该模式匹配的一组单词。

字符向量 'Joh?n\w*' 是一个正则表达式的示例。该字符串定义的模式以字母 Jo 开头,后面可跟,也可不跟字母 h(由 'h?' 指示),然后跟有字母 n,最后以任意数量的单词字符结尾(由 '\w*' 指示),此处的单词字符指字母、数字或下划字符。该模式与以下任意条目匹配:

Jon, John, Jonathan, Johnny

正则表达式提供了一种在大量文本中搜索特定字符子集的独特方式。正则表达式使您能够查找特定模式的字符,而不必像使用 strfind 等函数那样查找字符的完全匹配项。

例如,有多种表示公制速率的方式:

km/h
km/hr
km/hour
kilometers/hour
kilometers per hour

您可以通过发出五个单独的搜索命令在文本中查找以上任意词汇:

strfind(text, 'km/h');
strfind(text, 'km/hour');
% etc.

当然,为了提高效率,您也可以构建一个适用于所有这些搜索词汇的短语:

Flow-chart describing logic of example regular expression.

将此短语转换为正则表达式(本部分后面将会介绍),您将具有如下表达式:

pattern = 'k(ilo)?m(eters)?(/|\sper\s)h(r|our)?';

现在仅使用一个命令来查找一个或多个词汇:

text = ['The high-speed train traveled at 250 ', ...
   'kilometers per hour alongside the automobile ', ...
   'travelling at 120 km/h.'];
regexp(text, pattern, 'match')
ans =

  1×2 cell array

    {'kilometers per hour'}    {'km/h'}

有四个 MATLAB® 函数支持使用正则表达式搜索和替换字符。前三个函数在接受的输入值和返回的输出值方面类似。有关详细信息,请点击函数参考页的链接。

函数描述
regexp

匹配正则表达式。

regexpi

匹配正则表达式并忽略大小写。

regexprep

使用正则表达式替换部分文本。

regexptranslate

将文本转换为正则表达式。

调用前三个函数中的任何一个函数时,请在前两个输入参量中传递要解析的文本以及正则表达式。调用 regexprep 时,还需再传递一个额外的输入,该输入是一个表达式,用于指定替代的模式。

构建表达式的步骤

使用正则表达式在文本中搜索特定词涉及以下三个步骤:

  1. 确定字符串中的独特模式

    这需要根据字符形式的类同情况对要搜索的文本进行拆分。这些字符形式可以是一系列小写字母、一个美元符号后跟三个数字,然后跟有一个小数点等。

  2. 将每种模式表示为正则表达式

    使用本文档中所述的元字符和运算符将搜索模式的每个段表示为正则表达式。然后,将这些表达式段组合成单个表达式以在搜索时使用。

  3. 调用合适的搜索函数

    将要解析的文本传递给其中一个搜索函数(例如 regexpregexpi),或者传递给文本替代函数 regexprep

此部分中显示的示例搜索包含群组中五个朋友的联系信息的记录。该信息包括每个人的姓名、电话号码、居住地和电子邮件地址。目标是从文本中提取特定信息。

contacts = { ...
'Harry  287-625-7315  Columbus, OH  hparker@hmail.com'; ...
'Janice  529-882-1759  Fresno, CA  jan_stephens@horizon.net'; ...
'Mike  793-136-0975  Richmond, VA  sue_and_mike@hmail.net'; ...
'Nadine  648-427-9947  Tampa, FL  nadine_berry@horizon.net'; ...
'Jason  697-336-7728  Montrose, CO  jason_blake@mymail.com'};

此示例的第一部分构建一个表示标准电子邮件地址的格式的正则表达式。通过该表达式,此示例就可以在信息中搜索群组中一个朋友的电子邮件地址。Janice 的联系信息位于 contacts 元胞数组的第 2 行:

contacts{2}
ans =

    'Janice  529-882-1759  Fresno, CA  jan_stephens@horizon.net'

步骤 1 - 确定文本中的独特模式

典型的电子邮件地址包含以下标准部分:用户的帐户名称(后跟 @ 符号)、用户的 Internet 服务提供商 (ISP) 的名称、点(句点)以及该 ISP 所属的域。下表在左列中列出了这些部分,在右列中概述了每部分的格式。

电子邮件地址的独特模式每种模式的一般说明
以帐户名称开头
jan_stephens . . .
一个或多个小写字母和下划线
添加 '@'
jan_stephens@ . . .
@ 符号
添加 ISP
jan_stephens@horizon . . .
一个或多个小写字母,无下划线
添加点(句点)
jan_stephens@horizon. . . .
点(句点)字符
以域结尾
 jan_stephens@horizon.net
comnet

步骤 2 - 将每种模式表示为正则表达式

在此步骤中,您将步骤 1 中得到的一般格式转换为正则表达式的段。然后,将这些段添加到一起以构成整个表达式。

下表在最左侧的列中显示了每种字符模式的广义格式说明。(这是从步骤 1 的表的右列中继承过来的。)第二列显示表示字符模式的运算符或元字符。

每个段的说明模式
一个或多个小写字母和下划线[a-z_]+
@ 符号@
一个或多个小写字母,无下划线[a-z]+
点(句点)字符\.
comnet(com|net)

将这些模式组合成一个字符向量可得到完整的表达式:

email = '[a-z_]+@[a-z]+\.(com|net)';

步骤 3 - 调用合适的搜索函数

在此步骤中,您使用步骤 2 中得到的正则表达式来匹配群组中其中一个朋友的电子邮件地址。使用 regexp 函数执行搜索。

下面列出了此部分先前显示的联系信息。每个人的记录占用 contacts 元胞数组的一行:

contacts = { ...
'Harry  287-625-7315  Columbus, OH  hparker@hmail.com'; ...
'Janice  529-882-1759  Fresno, CA  jan_stephens@horizon.net'; ...
'Mike  793-136-0975  Richmond, VA  sue_and_mike@hmail.net'; ...
'Nadine  648-427-9947  Tampa, FL  nadine_berry@horizon.net'; ...
'Jason  697-336-7728  Montrose, CO  jason_blake@mymail.com'};

以下是步骤 2 中得到的表示电子邮件地址的正则表达式:

email = '[a-z_]+@[a-z]+\.(com|net)';

调用 regexp 函数,并传递 contacts 元胞数组的第 2 行以及 email 正则表达式。这将返回 Janice 的电子邮件地址。

regexp(contacts{2}, email, 'match')
ans =

  1×1 cell array

    {'jan_stephens@horizon.net'}

MATLAB 从左至右解析字符向量,并随着解析的进行“消减”该向量。如果找到匹配的字符,regexp 将会记录相应位置并继续解析字符向量(仅从最新匹配项结尾之后开始)。

执行相同调用,但这次是针对列表中的第五个人进行调用:

regexp(contacts{5}, email, 'match')
ans =

  1×1 cell array

    {'jason_blake@mymail.com'}

您也可以使用整个元胞数组作为输入参量,以搜索列表中每个人的电子邮件地址:

regexp(contacts, email, 'match');

运算符和字符

正则表达式可包含用于指定要匹配的模式的字符、元字符、运算符、词元和标志,如下面各部分所述:

元字符

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

元字符

描述

示例

.

任何单个字符,包括空白

'..ain' 与以 'ain' 结尾的五个连续字符序列匹配。

[c1c2c3]

包含在方括号中的任意字符。下列字符将按字面意义进行处理:$ | . * + ?-(不用于指示范围时)。

'[rp.]ain''rain''pain''.ain' 匹配。

[^c1c2c3]

未包含在方括号中的任意字符。下列字符将按字面意义进行处理:$ | . * + ?-(不用于指示范围时)。

'[^*rp]ain' 与以 'ain' 结尾的所有由四个字母组成的序列('rain''pain''*ain' 除外)匹配。例如,它与 'gain''lain''vain' 匹配。

[c1-c2]

c1c2 范围中的任意字符

'[A-G]'AG 范围中的单个字符匹配。

\w

任意字母、数字或下划线字符。对于英语字符集,\w 等同于 [a-zA-Z_0-9]

'\w*' 识别由字母、数字或下划线字符组成的词。

\W

字母、数字或下划线之外的任意字符。对于英语字符集,\W 等同于 [^a-zA-Z_0-9]

'\W*' 标识不是由任意字母、数字或下划线字符组合而成的词。

\s

任意空白字符;等同于 [ \f\n\r\t\v]

'\w*n\s' 与以字母 n 结尾且后跟空白字符的单词匹配。

\S

任意非空白字符;等同于 [^ \f\n\r\t\v]

'\d\S' 与数字(后跟任意非空白字符)匹配。

\d

任意数字;等同于 [0-9]

'\d*' 与任意数量的连续数字匹配。

\D

任意非数字字符;等同于 [^0-9]

'\w*\D\>' 与不以数字结尾的单词匹配。

\oN\o{N}

八进制值 N 的字符

'\o{40}' 与八进制 40 定义的空格字符匹配。

\xN\x{N}

十六进制值 N 的字符

'\x2C' 与十六进制 2C 定义的逗号字符匹配。

字符表示

运算符

描述

\a

警报(蜂鸣)

\b

退格符

\f

换页符

\n

换行符

\r

回车符

\t

水平制表符

\v

垂直制表符

\char

正则表达式中您要从字面上匹配(例如,使用 \\ 匹配单个反斜杠)的具有特殊含义的任意字符。

限定符

限定符指定某个模式必须出现在匹配文本中的次数。

限定符

表达式出现的次数

示例

expr*

0 次或连续多次。

'\w*' 与任意长度的单词匹配。

expr?

0 次或 1 次。

'\w*(\.m)?' 与单词或以扩展名 .m 结尾(此条件为可选条件)的单词匹配。

expr+

1 次或连续多次。

'<img src="\w+\.gif">'<img> HTML 标记匹配(当文件名包含一个或多个字符时)。

expr{m,n}

至少 m 次,但不超过连续 n 次。

{0,1} 等效于 ?

'\S{4,8}' 与四到八个非空白字符匹配。

expr{m,}

至少连续 m 次。

{0,}{1,} 分别等效于 *+

'<a href="\w{1,}\.html">'<a> HTML 标记匹配(当文件名包含一个或多个字符时)。

expr{n}

恰好连续 n 次。

等效于 {n,n}

'\d{4}' 与四个连续数字匹配。

限定符可以以三种模式显示,如下表所述。q 表示上表中的任意限定符。

模式

描述

示例

exprq

积极表达式:与尽可能多的字符匹配。

给定文本 '<tr><td><p>text</p></td>',表达式 '</?t.*>' 与介于 <tr/td> 之间的所有字符匹配:

'<tr><td><p>text</p></td>'

exprq?

消极表达式:与所需的尽可能少的字符匹配。

给定文本 '<tr><td><p>text</p></td>',表达式 '</?t.*?>' 在第一次出现右尖括号 (>) 时结束每个匹配项:

'<tr>' '<td>' '</td>'

exprq+

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

给定文本 '<tr><td><p>text</p></td>',表达式 '</?t.*+>' 不返回任何匹配项,这是因为右尖括号是使用 .* 捕获的且不进行重新扫描。

分组运算符

分组运算符允许您捕获词元,将一个运算符应用于多个元素或在特定组中禁止追溯。

分组运算符

描述

示例

(expr)

将表达式元素分组并捕获词元。

'Joh?n\s(\w*)' 捕获一个词元,该词元包含名字为 JohnJon 的任何人的姓氏。

(?:expr)

分组但不捕获词元。

'(?:[aeiou][^aeiou]){2}' 与两个连续的元音后跟非元音(例如 'anon')的模式匹配。

不进行分组时,'[aeiou][^aeiou]{2}' 与元音后跟两个非元音匹配。

(?>expr)

以原子方式分组。不在组中追溯以完成匹配,并且不捕获词元。

'A(?>.*)Z''AtoZ' 不匹配,但 'A(?:.*)Z' 与其匹配。使用原子组时,Z 将使用 .* 进行捕获并且不进行重新扫描。

(expr1|expr2)

匹配表达式 expr1 或表达式 expr2

如果存在与 expr1 匹配的项,则将忽略 expr2

您可以在左括号后包括 ?:?> 以禁用词元或以原子方式分组。

'(let|tel)\w+' 匹配包含 lettel 但不以它们结尾的单词。

定位点

表达式中的定位点与字符向量或单词的开头或结尾匹配。

定位点

与以下项匹配

示例

^expr

输入文本的开头。

'^M\w*' 与以 M 作为文本开头的单词匹配。

expr$

输入文本的结尾。

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

\<expr

单词开头。

'\<n\w*' 与以 n 开头的任何单词匹配。

expr\>

单词结尾。

'\w*e\>' 与以 e 结尾的任何单词匹配。

环顾断言

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

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

环顾断言

描述

示例

expr(?=test)

向前查找与 test 匹配的字符。

'\w*(?=ing)' 匹配后跟 ing 的词汇,例如输入文本 'Flying, not falling.' 中的 'Fly''fall'

expr(?!test)

向前查找与 test 不匹配的字符。

'i(?!ng)' 匹配字母 i 的不后跟 ng 的实例。

(?<=test)expr

向后查找与 test 匹配的字符。

'(?<=re)\w*' 匹配紧跟 're' 的词汇,例如输入文本 'renew, reuse, recycle' 中的 'new''use''cycle'

(?<!test)expr

向后查找与 test 不匹配的字符。

'(?<!\d)(\d)(?!\d)' 与一位数字匹配(不紧随其他数字前后的数字)。

如果您在表达式之前指定前向断言,则运算等同于逻辑 AND

运算

描述

示例

(?=test)expr

同时与 testexpr 匹配。

'(?=[a-z])[^aeiou]' 与辅音匹配。

(?!test)expr

匹配 expr,但不匹配 test

'(?![aeiou])[a-z]' 与辅音匹配。

有关详细信息,请参阅正则表达式中的前向断言

逻辑和条件运算符

逻辑和条件运算符允许您测试给定条件的状态,然后使用结果确定哪个模式(如果有)与下一条件匹配。这些运算符支持逻辑 ORifif/else 条件。(对于 AND 条件,请参阅环顾断言。)

条件可以是词元环顾断言(?@cmd) 形式的动态表达式。动态表达式必须返回逻辑值或数值。

条件运算符

描述

示例

expr1|expr2

匹配表达式 expr1 或表达式 expr2

如果存在与 expr1 匹配的项,则将忽略 expr2

'(let|tel)\w+' 匹配以 lettel 开头的单词。

(?(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 开头时)。

词元运算符

词元是您通过将正则表达式的部分括在括号中而定义的匹配文本的部分。您可以按词元在文本中的顺序引用该词元(顺序词元),或将名称分配给词元以便于代码维护和使输出更易于阅读。

顺序词元运算符

描述

示例

(expr)

在词元中捕获与括起来的表达式匹配的字符。

'Joh?n\s(\w*)' 捕获一个词元,该词元包含名字为 JohnJon 的任何人的姓氏。

\N

匹配第 N 个词元。

'<(\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)

在命名词元中捕获与括起来的表达式匹配的字符。

'(?<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)

如果找到命名词元,则匹配 expr1。否则,匹配 expr2

'Mr(?<sex>s?)\..*?(?(sex)her|his) \w*' 匹配包含 her 的文本(当文本以 Mrs 开头时),或包含 his 的文本(当文本以 Mr 开头时)。

注意

如果表达式具有嵌套括号,则 MATLAB 捕获对应于最外层括号的词元。例如,给定搜索模式 '(and(y|rew))',MATLAB 将为 'andrew' 但不为 'y''rew' 创建一个词元。

有关详细信息,请参阅正则表达式中的词元

动态表达式

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

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

运算符

描述

示例

(??expr)

解析 expr 并将得到的项包括在匹配表达式中。

解析后,expr 必须对应于完整的有效正则表达式。使用反斜杠转义字符 (\) 的动态表达式需要两个反斜杠:一个用于 expr 的初始解析,一个用于完整匹配。

'^(\d+)((??\\w{$1}))' 通过读取匹配项开头的数字确定匹配的字符数。动态表达式括在另一组括号中,以便在词元中捕获生成的匹配项。例如,匹配 '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 运算符,可以在代码中插入注释,以使代码更易于维护。根据输入文本进行匹配时,MATLAB 会忽略注释的文本。

字符

描述

示例

(?#comment)

在正则表达式中插入注释。匹配输入时将忽略注释文本。

'(?# Initial digit)\<\d\w+' 包括一个注释,并匹配以一个数字开头的单词。

搜索标志

搜索标志修改匹配表达式的行为。

标志

描述

(?-i)

匹配字母大小写(regexpregexprep 的默认值)。

(?i)

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

(?s)

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

(?-s)

将模式中的点与并非换行符的任意字符匹配。

(?-m)

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

(?m)

匹配行开头和结尾的 ^$ 元字符。

(?-x)

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

(?x)

在匹配时忽略空格字符和注释。使用 '\ ''\#' 匹配空白和 # 字符。

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

(?i)\w*

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

(?i:\w*)

后面的语法允许您更改较大表达式的一部分的行为。

另请参阅

| | | |

相关主题