Main Content

构建模式表达式

自 R2020b 开始提供

模式是帮助搜索和修改文本的工具。与正则表达式类似,模式定义匹配文本的规则。模式可与文本搜索函数(如 containsmatchesextract)结合使用来指定这些函数作用于文本的哪些部分。您可以使用模式函数、运算符和字面文本,以类似于构建数学表达式的方式构建模式表达式。由于构建模式表达式是开放式的,因此模式可能变得相当复杂。分步构建模式并使用 maskedPatternnamedPattern 等函数有助于组织复杂的模式。

构建简单模式

最简单的模式是从单模式函数构建的。例如,lettersPattern 匹配任何字母字符。有许多模式函数用于匹配不同类型的字符和文本的其他特征。这些函数的列表可以在 pattern 参考页上找到。

txt = "abc123def";
pat = lettersPattern;
extract(txt,pat)
ans = 2x1 string
    "abc"
    "def"

模式通过使用 plus(+) 运算符与其他模式和字面文本相结合。此运算符按照在模式表达式中定义的顺序将模式和文本附加在一起。组合模式只匹配相同顺序的文本。在此示例中,“YYYY/MM/DD”不是匹配项,因为文本末尾必须有包含四个字母的字符串。

txt = "Dates can be expressed as MM/DD/YYYY, DD/MM/YYYY, or YYYY/MM/DD";
pat = lettersPattern(2) + "/" + lettersPattern(2) + "/" + lettersPattern(4);
extract(txt,pat)
ans = 2x1 string
    "MM/DD/YYYY"
    "DD/MM/YYYY"

使用 or(|) 运算符指示两个指定模式中只要有一个模式匹配文本段即可。如果两个模式都无法匹配,则模式表达式的匹配失败。

txt = "123abc";
pat = lettersPattern|digitsPattern;
extract(txt,pat)
ans = 2x1 string
    "123"
    "abc"

一些模式函数将模式作为其输入,并以某种方式修改它们。例如,optionalPattern 会尽可能匹配指定的模式,但它并非成功匹配的必需条件。

txt = ["123abc" "abc"];
pat = optionalPattern(digitsPattern) + lettersPattern;
extract(txt,pat)
ans = 1x2 string
    "123abc"    "abc"

边界模式

边界模式是一种特殊类型的模式,它不匹配字符,而是匹配指定字符类型和其他字符之间的边界,或匹配文本段的开头或结尾。例如,digitBoundary 匹配数字字符和非数字字符之间的边界,以及数字字符和文本的开头或结尾之间的边界。它不匹配数字字符本身。对于像 split 这样的函数,边界模式是有用的定界符。

txt = "123abc";
pat = digitBoundary;
split(txt,pat)
ans = 3x1 string
    ""
    "123"
    "abc"

边界模式是特殊模式,因为可以使用 not(~) 运算符对其求反。当以这种方式求反时,边界模式在不满足上述要求的字符之前或之后进行匹配。例如,~digitBoundary 匹配满足以下条件的两者之间的边界:

  • 都是数字的两个字符

  • 都是非数字的两个字符

  • 一个非数字字符和一段文本的开头或末尾

使用 replace"|" 字符标记 ~digitBoundary 匹配的位置。

txt = "123abc";
pat = ~digitBoundary;
replace(txt,pat,"|")
ans = 
"1|2|3a|b|c|"

分步构建复杂模式

有时简单模式不足以解决问题,需要更复杂的模式。随着模式表达式的增加,理解它匹配什么内容会变得困难。简化构建复杂模式的一种方法是单独构建模式的每个部分,然后将这些部分组合成单一模式表达式。

例如,电子邮件地址使用 local_part@domain.TLD 形式。三个标识符(local_part、domain 和 TLD)都必须为数字、字母和下划线字符的组合。要构建完整模式,首先要为标识符定义模式。构建一个模式,用它匹配一个字母或数字字符或一个下划线字符。

identCharacters = alphanumericsPattern(1) | "_";

现在,使用 asManyOfPattern 来匹配 identCharacters 的一个或多个连续实例。

identifier = asManyOfPattern(identCharacters,1);

接下来,构建一个模式,用它匹配包含多个标识符的电子邮件地址。

emailPattern = identifier + "@" + identifier + "." + identifier;

通过查看该模式与以下示例电子邮件地址的匹配效果来测试模式。

exampleEmails = ["janedoe@mathworks.com" 
    "abe.lincoln@whitehouse.gov"
    "alberteinstein@physics.university.edu"];
matches(exampleEmails,emailPattern)
ans = 3x1 logical array

   1
   0
   0

尽管所有电子邮件地址都是有效的,但该模式还是无法匹配其中几个示例电子邮件地址。local_part 和 domain 都可以由一系列用句点分隔的标识符组成。使用 identifier 模式构建能够匹配一系列标识符的模式。asManyOfPattern 匹配尽可能多的指定模式的并发实例,但如果没有,模式的其余部分仍然能够成功匹配。

identifierSeries = asManyOfPattern(identifier + ".") + identifier;

使用此模式构建一个新 emailPattern,它可以匹配所有示例电子邮件地址。

emailPattern = identifierSeries + "@" + identifierSeries + "." + identifier;
matches(exampleEmails,emailPattern)
ans = 3x1 logical array

   1
   1
   1

组织模式显示

复杂的模式有时很难阅读和解释,尤其是对于那些不熟悉模式结构的人来说。例如,emailPattern 在显示时就又长又难读。

emailPattern
emailPattern = pattern
  Matching:

    asManyOfPattern(asManyOfPattern(alphanumericsPattern(1) | "_",1) + ".") + asManyOfPattern(alphanumericsPattern(1) | "_",1) + "@" + asManyOfPattern(asManyOfPattern(alphanumericsPattern(1) | "_",1) + ".") + asManyOfPattern(alphanumericsPattern(1) | "_",1) + "." + asManyOfPattern(alphanumericsPattern(1) | "_",1)

显示难以阅读的问题部分在于存在许多重复的 identifier 模式。如果此模式的确切细节对模式的用户不重要,则可以使用 maskedPattern 隐藏 identifier 模式的显示。此函数创建一个新模式,其中 identifier 显示为掩码,而改为显示变量名称 "identifier"。您也可以指定显示不同名称。通过在显示的模式中点击“Show all details”,可以访问采用这种掩码方式的模式的详细信息。

identifier = maskedPattern(identifier);
identifierSeries = asManyOfPattern(identifier + ".") + identifier
identifierSeries = pattern
  Matching:

    asManyOfPattern(identifier + ".") + identifier

  Use details to show more information

可以使用 namedPattern 函数进一步组织模式。namedPattern 将模式指定为某个命名模式,当与其他模式组合时,该模式会更改显示方式。电子邮件地址有几个重要部分,local_part@domain.TLD,每个部分都有自己的匹配规则。为每个部分创建一个命名模式。

localPart = namedPattern(identifierSeries,"local_part");

命名模式可以嵌套,以进一步描述模式的各个部分。要嵌套命名模式,请使用若干命名模式构建一个模式,然后将该模式指定为一个命名模式。例如,Domain.TLD 可分为域、子域和顶层域 (TLD)。为 domain.TLD 的每个部分创建命名模式。

subdomain = namedPattern(identifierSeries,"subdomain");
domainName = namedPattern(identifier,"domainName");
tld = namedPattern(identifier,"TLD");

的各组成部分的命名模式嵌套在另一个命名模式 domain 下。

domain = optionalPattern(subdomain + ".") + ...
            domainName + "." + ...
            tld;
domain = namedPattern(domain);

将这些模式组合成一个命名模式 emailPattern。在 emailPattern 的显示中,您可以看到每个命名模式及其匹配项,以及关于任何嵌套命名模式的信息。

emailPattern = localPart + "@" + domain
emailPattern = pattern
  Matching:

    local_part + "@" + domain

  Using named patterns:

    local_part  : asManyOfPattern(identifier + ".") + identifier
    domain      : optionalPattern(subdomain + ".") + domainName + "." + TLD
      subdomain : asManyOfPattern(identifier + ".") + identifier
      domainName: identifier
      TLD       : identifier

  Use details to show more information

您可以通过对模式进行点索引来访问命名模式和嵌套命名模式。例如,通过从 emailPatterndomain 的点索引然后到 subdomain 的点索引,可以访问嵌套的命名模式 subdomain

emailPattern.domain.subdomain
ans = pattern
  Matching:

    asManyOfPattern(identifier + ".") + identifier

  Use details to show more information

点赋值可用于更改命名模式,而不需要重写模式表达式的其余部分。

emailPattern.domain = "mathworks.com"
emailPattern = pattern
  Matching:

    local_part + "@" + domain

  Using named patterns:

    local_part: asManyOfPattern(identifier + ".") + identifier
    domain    : "mathworks.com"

  Use details to show more information

Copyright 2020 The MathWorks, Inc.

另请参阅

| | | | |

相关主题