You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Perl正则匹配后@-与@+数组长度不同的原因及验证问题

Perl正则中@-与@+数组长度差异的原因及验证代码有效性分析

问题背景

原本预期Perl正则匹配成功后,@-和@+数组长度应当一致,但实际测试发现两者存在差异。示例脚本及运行结果如下:

示例脚本

#!/usr/bin/perl -w

use strict;
use warnings;

use v5.20.0;

use Data::Dumper;
$Data::Dumper::Terse = 1;

my $rex = '([a-z]+) | ([0-9]+) | ([A-Z]+)';

my $str = '9999';

if ( $str =~ m/$rex/x ) {
    say Dumper(\@{^CAPTURE});
    say Dumper(\@-);
    say Dumper(\@+);
}

运行输出

[
  undef,
  '9999'
]

[
  0,
  undef,
  0
]

[
  4,
  undef,
  4,
  undef
]

从结果可见:@-不会为末尾未被尝试匹配的分组添加undef元素,而@+会包含所有定义过的捕获组对应的位置(未匹配则为undef)。


一、@-与@+长度差异的原因

Perl中@-和@+数组的设计目标不同,导致了这种长度差异:

  • @-数组记录的是实际参与过匹配尝试的分组的起始位置:索引0对应整个匹配$&的起始位置,后续索引依次对应$1、$2...这些被引擎尝试匹配过的分组的起始位置。如果某个捕获组所在的分支根本没被执行(比如示例中第三个([A-Z]+)分支,因为第二个分支已匹配成功,引擎不会再尝试第三个分支),该分组不会被加入@-,因此数组长度不会包含这类未尝试的分组。
  • @+数组的设计是严格对应正则表达式中所有定义的捕获组:索引0对应整个匹配的结束位置,后续索引依次对应每一个捕获组(不管是否被尝试匹配)的结束位置。对于未被尝试或匹配失败的分组,对应位置填充undef,因此数组长度等于捕获组总数+1。

这种差异是Perl正则引擎的历史实现逻辑,@-聚焦于实际发生的匹配行为,@+则覆盖所有定义的捕获组,满足开发者对所有分组位置的查询需求。


二、验证代码的通用性分析

针对验证代码:

if ( $str =~ m/$rex/x ) {
     scalar(@{[$&, @{^CAPTURE}]}) == scalar(@-) or die;
}

该代码的逻辑是:合并$&(整个匹配内容)与@{^CAPTURE}(所有被尝试过的捕获组结果,未匹配则为undef)的数组长度,与@-的长度做对比。

这个验证逻辑适用于所有匹配成功的场景:

  • @{^CAPTURE}的元素数量等于所有被引擎尝试过的捕获组的数量(无论匹配成功与否);
  • 加上$&后,数组总长度为1 + 被尝试的捕获组数量,正好等于@-的长度(@-索引0对应$&的起始,后续每个索引对应一个被尝试的捕获组)。

因此只要正则匹配成功,该验证逻辑都成立。


内容的提问来源于stack exchange,提问作者Britton Kerin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 13:17:56