Perl正则表达式超详细教程(10)

如果使用匿名捕获,对and和or这样无关紧要,却有可能改变匹配行为的内容,可以将其放进一个无关的分组中。这样不会对原有的其余正则表达式产生任何影响:

$str = "xiaofang or longshuai"; if ($str =~ /(\w+) (?:or|and) (\w+)/){ print "name1: $1, name2: $2\n"; }

注意上面仍然使用$2引用第三个括号。

同样,如果要在正则内部使用反向引用,也一样使用\2来引用第三个括号。

另外,在前文还介绍过一个n修饰符,它也表示非捕获仅分组行为。但它只对普通分组有效,对命名分组无效。且因为它是修饰符,它会使所有的普通分组都变成非捕获模式。

$str = "xiaofang or longshuai"; if ($str =~ /(\w+) (or|and) (\w+)/n){ print "name1: $1, name2: $2\n"; }

由于上面开启了n修饰符,使得3个普通分组括号都变成非捕获仅分组行为,所以\1和$1都无法使用。除非正则中使用了命名分组。

命名捕获

命名捕获是指将捕获到的内容放进分组,这个分组是有名称的分组,所以后面可以使用分组名去引用已捕获进这个分组的内容。除此之外,和普通分组并无区别。

当要进行命名捕获时,使用(?<NAME>)的方式替代以前的分组括号()即可。例如,要匹配abc并将其分组,以前普通分组的方式是(abc),如果将其放进命名为name1的分组中:(?<name1>abc)。

当使用命名捕获的时候,要在正则内部引用这个命名捕获,除了可以使用序号类的绝对引用(如\1或\g1或\g{1}),还可以使用以下任意一种按名称引用方式:

\g{NAME}

\k{NAME}

\k<NAME>

\k'NAME'

如果要在正则外部引用这个命名捕获,除了可以使用序号类的绝对应用(如$1),还可以使用$+{NAME}的方式。

实际上,后一种引用方式的本质是perl将命名捕获的内容放进了一个名为%+的特殊hash类型中,所以可以使用$+{NAME}的方式引用,如果你不知道这一点,那就无视与此相关的内容即可,不过都很简单,一看就懂。

例如:

$str = "ma xiaofang or ma longshuai"; if ($str =~ / (?<firstname>\w+)\s # firstname -> ma (?<name1>\w+)\s # name1 -> xiaofang (?:or|and)\s # group only, no capture \g1\s # \g1 -> ma (?<name2>\w+) # name2 -> longshuai /x){ print "$1\n"; print "$2\n"; print "$3\n"; # 或者指定名称来引用 print "$+{firstname}\n$+{name1}\n$+{name2}\n"; }

其中上述代码中的\g1还可以替换为\1、\g{firstname}、\k{firstname}或\k<firstname>。

通过使用命名捕获,可以无视序号,直接使用名称即可准确引用。

固化分组

首先固化分组不是一种分组,所以无法去引用它。它和"占有优先"匹配模式(贪婪匹配、惰性匹配、占有优先匹配三种匹配模式,见后文)是等价的除了这两种称呼,在不同的书、不同的语言里还有一种称呼:原子匹配。

它的表示形式类似于分组(?>),所以有些地方将其称呼为"固化分组"。再次说明,固化分组不是分组,无法进行引用。如果非要将其看作是分组,可以将其理解为被限定的匿名分组:不捕获,只分组。

按照"占有优先"的字面意义来理解比较容易:只要匹配成功了,就绝不回溯。

如果按照固化分组的概念来理解,就是将匹配成功的内容放进分组后,将其固定,不允许进行回溯。但是需要注意,这里的不回溯是放进分组中的内容不会回溯给分组外面,而分组内部的内容是可以回溯的

如果不知道什么是回溯,看完下面的例子就明白。

例如"hello world"可以被hel.* world成功匹配,但不能被hel(?>.*) world匹配。因为正常情况下,.*匹配到所有内容,然后往回释放已匹配的内容直到释放完空格为止,这种往回释放字符的行为在正则术语中称为"回溯"。而固化分组后,.*已匹配后面所有内容,这些内容一经匹配绝不交回,即无法回溯。

但是,如果正则表达式是hel(?>.* world),即将原来分组外面的内容放进了分组内部,这时在分组内部是会回溯的,也就是说能匹配"hello world"。

$str="ma longshuai gao xiaofang"; if($str =~ /ma (?>long.*)/){ # 成功 print "matched\n"; } if($str =~ /ma (?>long.*)gao/){ # 失败 print "matched\n"; } if($str =~ /ma (?>long.*gao)/){ # 成功 print "matched\n"; } if($str =~ /ma (?>long.*g)ao/){ # 成功 print "matched\n"; }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/e1a716f6fc1f35a6ad219d4af05ea1f5.html