Main Content

正则表达式中的词元

简介

正则表达式中使用的括号不仅将该表达式的元素分组在一起,而且会为找到的与该组条件匹配的任何匹配项指定词元。您可以使用词元匹配同一文本的其他部分。使用词元的一个好处是,词元会记住所匹配的内容,因此您可以在搜索或替换过程中重新调用和重用匹配的文本。

表达式中的每个词元都会被分配一个数字,从 1 开始,从左至右顺序递增。要在表达式的后面引用某个词元,请使用反斜杠并后跟词元编号进行引用。例如,引用表达式中第三组括号生成的词元时,请使用 \3

举一个简单的例子,如果您要搜索字符数组中相同顺序的字母,可以捕获第一个字母作为词元,然后搜索紧随其后的匹配字符。在以下所示的表达式中,只要 regexp 与字符数组中的任何非空白字符匹配,(\S) 短语就会创建一个词元。表达式的第二部分 '\1' 查找同一字符第一个实例后面紧跟的第二个实例。

poe = ['While I nodded, nearly napping, ' ...
       'suddenly there came a tapping,'];

[mat,tok,ext] = regexp(poe, '(\S)\1', 'match', ...
               'tokens', 'tokenExtents');
mat
mat =

  1×4 cell array

    {'dd'}    {'pp'}    {'dd'}    {'pp'}

元胞数组 tok 包含多个元胞数组,其中每个元胞数组都包含一个词元。

tok{:}
ans =

  1×1 cell array

    {'d'}


ans =

  1×1 cell array

    {'p'}


ans =

  1×1 cell array

    {'d'}


ans =

  1×1 cell array

    {'p'}

元胞数组 ext 包含多个数值数组,其中每个数值数组都包含一个词元的开始索引和结束索引。

ext{:}
ans =

    11    11


ans =

    26    26


ans =

    35    35


ans =

    57    57

另一个示例捕获匹配的 HTML 标记对组(例如 <a></a>)以及这些标记之间的文本。用于此示例的表达式为

expr = '<(\w+).*?>.*?</\1>';

该表达式的第一部分 '<(\w+)' 匹配左尖括号 (<),后跟一个或多个字母、数字或下划线字符。封闭的圆括号捕获左尖括号后面的词元字符。

该表达式的第二部分 '.*?>.*?' 匹配此 HTML 标记的其余部分(一直到 > 的字符),以及可能位于下一个左尖括号之前的任何字符。

最后一部分 '</\1>' 匹配结尾的 HTML 标记中的所有字符。此标记由 </tag> 序列组成,其中 tag 表示捕获为词元的任何字符。

hstr = '<!comment><a name="752507"></a><b>Default</b><br>';
expr = '<(\w+).*?>.*?</\1>';

[mat,tok] = regexp(hstr, expr, 'match', 'tokens');
mat{:}
ans =

    '<a name="752507"></a>'


ans =

    '<b>Default</b>'
tok{:}
ans =

  1×1 cell array

    {'a'}


ans =

  1×1 cell array

    {'b'}

多个词元

下面是一个如何为词元分配值的示例。假定您要搜索以下文本:

andy ted bob jim andrew andy ted mark

您选择使用以下搜索模式来搜索上述文本:

and(y|rew)|(t)e(d)

此模式包含三个生成词元的带括号表达式。当您最后执行搜索时,系统将为每个匹配项生成以下词元。

匹配项

词元 1

词元 2

andy

y

 

ted

t

d

andrew

rew

 

andy

y

 

ted

t

d

只会使用最高级别的括号。例如,如果搜索模式 and(y|rew) 找到文本 andrew,则会为词元 1 分配值 rew。但是,如果使用搜索模式 (and(y|rew)),则会为词元 1 分配值 andrew

不匹配的词元

对于正则表达式中指定的词元,如果在待查文本中没有匹配项,regexpregexpi 会返回一个空字符向量 ('') 作为词元输出,同时还会返回一个范围,用来标记词元在字符串中预期出现的位置。

此处所示的示例会对一个字符向量执行 regexp,该字符向量指定了从 MATLAB® tempdir 函数返回的路径。正则表达式 expr 包括六个词元设定符,每个设定符代表路径的一部分。第三个设定符 [a-z]+ 在字符向量中没有匹配项,因为此部分的路径 Profiles 是以大写字母开头的:

chr = tempdir
chr =

    'C:\WINNT\Profiles\bpascal\LOCALS~1\Temp\'
expr = ['([A-Z]:)\\(WINNT)\\([a-z]+)?.*\\' ...
        '([a-z]+)\\([A-Z]+~\d)\\(Temp)\\'];

[tok, ext] = regexp(chr, expr, 'tokens', 'tokenExtents');

如果在文本中未找到词元,regexp 会返回一个空字符向量 ('') 作为词元以及一个包含词元范围的数值数组。而范围的第一个数字为字符串索引,用于标记词元预期出现的位置;范围的第二个数字为第一个数字减 1。

在此示例中,表达式中指定的第三个词元为空词元,因此返回的第三个词元为空:

tok{:}
ans =

  1×6 cell array

    {'C:'}    {'WINNT'}    {0×0 char}    {'bpascal'}    {'LOCALS~1'}    {'Temp'}

变量 ext 中返回的第三个词元范围的起始索引设置为 10,这是不含匹配项的词 Profiles 在路径中的起始位置。范围结束索引设置为起始索引减 1,也就是 9:

ext{:}
ans =

     1     2
     4     8
    10     9
    19    25
    27    34
    36    39

替代文本中的词元

在替代文本中使用词元时,请使用 $1$2 等符号,而不要使用 \1\2 等符号来引用词元。此示例捕获两个词元并颠倒它们的顺序。第一个标文 $1'Norma Jean',第二个标文 $2'Baker'。请注意,regexprep 返回修改后的文本,而不是起始索引的向量。

regexprep('Norma Jean Baker', '(\w+\s\w+)\s(\w+)', '$2, $1')
ans =

    'Baker, Norma Jean'

命名捕获

如果您在表达式中使用许多词元,则为这些词元分配名称可能会很有帮助,而不必跟踪为哪个词元分配了哪个词元编号。

引用表达式中的命名词元时,请使用语法 \k<name>,而不要使用 \1\2 等数字:

poe = ['While I nodded, nearly napping, ' ...
       'suddenly there came a tapping,'];

regexp(poe, '(?<anychar>.)\k<anychar>', 'match')
ans =

  1×4 cell array

    {'dd'}    {'pp'}    {'dd'}    {'pp'}

指定词元还有助于标记 MATLAB 正则表达式函数的输出。当您处理许多文本段时尤其如此。

例如,从多个字符向量中解析街道地址的不同部分。为表达式中的每个词元分配了一个短名称:

chr1 = '134 Main Street, Boulder, CO, 14923';
chr2 = '26 Walnut Road, Topeka, KA, 25384';
chr3 = '847 Industrial Drive, Elizabeth, NJ, 73548';

p1 = '(?<adrs>\d+\s\S+\s(Road|Street|Avenue|Drive))';
p2 = '(?<city>[A-Z][a-z]+)';
p3 = '(?<state>[A-Z]{2})';
p4 = '(?<zip>\d{5})';

expr = [p1 ', ' p2 ', ' p3 ', ' p4];

正如以下结果所展示的,您可以通过命名词元使输出更易于使用:

loc1 = regexp(chr1, expr, 'names')
loc1 = 

  struct with fields:

     adrs: '134 Main Street'
     city: 'Boulder'
    state: 'CO'
      zip: '14923'
loc2 = regexp(chr2, expr, 'names')
loc2 = 

  struct with fields:

     adrs: '26 Walnut Road'
     city: 'Topeka'
    state: 'KA'
      zip: '25384'
loc3 = regexp(chr3, expr, 'names')
loc3 = 

  struct with fields:

     adrs: '847 Industrial Drive'
     city: 'Elizabeth'
    state: 'NJ'
      zip: '73548'

另请参阅

| |

相关主题