Regex 为什么我只能得到第一个捕获组?

Regex 为什么我只能得到第一个捕获组?,regex,perl,regex-group,Regex,Perl,Regex Group,(并且没有帮助我) 在Linux中分析/proc/stat的一个问题时,我开始编写一个小实用程序,但是我无法按照我想要的方式获取捕获组。 代码如下: #/usr/bin/perl 严格使用; 使用警告; if(open)(my$fh,Perl的正则表达式引擎将只记住重复表达式中的最后一个捕获组。如果要在单独的捕获组中捕获每个数字,则一个选项是使用显式正则表达式模式: if (open(my $fh, '<', my $file = '/proc/stat')) { while (&

(并且没有帮助我)

在Linux中分析
/proc/stat
的一个问题时,我开始编写一个小实用程序,但是我无法按照我想要的方式获取捕获组。 代码如下:

#/usr/bin/perl
严格使用;
使用警告;

if(open)(my$fh,Perl的正则表达式引擎将只记住重复表达式中的最后一个捕获组。如果要在单独的捕获组中捕获每个数字,则一个选项是使用显式正则表达式模式:

if (open(my $fh, '<', my $file = '/proc/stat')) {
    while (<$fh>) {
        if (my ($cpu, @vals) = /^cpu(\d*)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/) {
            print "$cpu $#vals\n";
        }
    }
    close($fh);
} else {
    die "$file: $!\n";
}

if(open)(my$fh),按照示例输入,while循环中的以下内容应该可以工作

if (/^cpu(\d*)/) {
    my $cpu = $1;
    my (@vals) = /(?:\s+(\d+))+/g;
    print "$cpu $#vals\n";
}
只是补充一下:

您可以使用一个组捕获多个值(使用g-modifier),但随后必须拆分语句

    if (my ($cpu) = /^cpu(\d*)(?:\s+(\d+))+$/) {
        my @vals= /(?:\s+(\d+))/g;
        print "$cpu $#vals\n";
    }
替换

while(){
如果(my($cpu,@VAL)=/^cpu(\d*)(?:\s+(\d+)+$/){

while(){
我的@vals;
如果(my($cpu)=/^cpu(\d*)(?:\s+(\d+)({push(@vals,$^N)}))+$/){

执行我想要的操作(需要perl 5.8或更高版本)。

仅捕获单个模式的最后一个重复匹配

相反,您可以只拆分行,然后检查并调整第一个字段

while (<$fh>) {
    my ($cpu, @vals) = split;
    next if not $cpu =~ s/^cpu//;
    print "$cpu $#vals\n";
}
正则表达式返回两个项,每个项在
映射中都是
split
,但第一个项只是按原样传递到
$cpu
(一个数字或一个空字符串),而另一个项生成数字

这两种方法都能在我的测试中产生所需的输出。

在的练习中,我们陈述了一个问题,用两个简单的正则表达式很容易解决,但用一个正则表达式很难解决(但在中,我拔出了大炮)我们之所以不告诉人们这些,是因为我们想强调用一个正则表达式写出所有内容的自然行为。其他答案中的一些曲解让我想起了这一点,我不想保留其中任何一个

首先是只处理感兴趣的行的问题。然后,一旦我们有了那行,就抓住所有的数字。将问题陈述翻译成代码是非常简单和直接的。这里没有技巧,因为断言和锚做了大部分工作:

use v5.10;

while( <DATA> ) {
    next unless /\A cpu(\d*) \s /ax;
    my $cpu = $1;
    my @values = / \b (\d+) \b /agx;
    say "$cpu " . @values;
    }

__END__
cpu  2709779 13999 551920 11622773 135610 0 194680 0 0 0
cpu0 677679 3082 124900 11507188 134042 0 164081 0 0 0
cpu1 775182 3866 147044 38910 135 0 15026 0 0 0
cpu2 704411 3024 143057 37674 1272 0 8403 0 0 0
cpu3 552506 4025 136918 38999 160 0 7169 0 0 0
intr 176332106  ...
使用v5.10;
而(){
下一步除非/\A cpu(\d*)\s/ax;
my$cpu=$1;
我的@values=/\b(\d+)\b/agx;
说“$cpu”。@values;
}
__结束__
cpu 2709779 13999 551920 11622773 135610 0 194680 0 0
cpu0 677679 3082 124900 11507188 134042 0 164081 0 0
cpu1 775182 3866 147044 38910 135 0 15026 0 0
cpu2 704411 3024 143057 37674 1272 0 8403 0 0
cpu3 552506 4025 136918 38999 160 0 7169 0 0 0
国际电话176332106。。。

请注意,OP仍然需要决定如何处理无尾随数字的
cpu
情况。不知道您想如何处理空字符串。

他就是我的例子。我想我应该添加它,因为我喜欢简单的代码。它还允许“cpu7”无尾随数字

#!/usr/bin/perl
use strict;
use warnings;

my $file = "/proc/stat";
open(my $fh, "<", $file) or die "$file: $!\n";
while (<$fh>) 
{
  if ( /^cpu(\d+)(\s+)?(.*)$/ ) 
  {
    my $cpu = $1; 
    my $vals = scalar split( /\s+/, $3 ) ;
    print "$cpu $vals\n";
  }
}
close($fh);
!/usr/bin/perl
严格使用;
使用警告;
my$file=“/proc/stat”;

打开(我的$fh,"问题是'cpu'的数字数量随着时间的推移而变化,可能会添加更多的值。我觉得这是perl中的一个缺陷,因为整行都是匹配的。如何:使用当前的正则表达式断言每行都匹配,然后使用字符串拆分将每一个数字项作为数组中的一个单独元素隔离?这是基本的ally@Tim Biegeleisen在评论中所说的。这基本上就是@Tim Biegeleisen在评论中所说的。他有固定数量的捕获组。你的解决方案是高效的(但有点复杂)一个没有固定数量的捕获组。有趣的变体,但比我的原始代码IMHO更难理解。
/x
有什么用,为什么不使用“/^cpu([0-9]*)(.*)$/`@U.Windl”原始代码“…实际上不做你需要的事情?这是的。
/x
只允许内部有文字空格(以及注释和换行符),以便于阅读。不需要。我删除了
$
,因为它不需要,所以
*
始终匹配到结尾。@U.Windl“比我原来的代码IMHO更难理解”---是的,绝对同意,第二个选项有点棘手。我喜欢它作为一种古玩。我推荐第一个。在第一个代码示例中,您总是测试
$cpu
是预期值。因为您要对每一行进行测试,所以您可以先进行测试,然后只有在成功时才进行拆分。假设开始时的匹配比拆分更有效,你可以先
下一步,除非/^cpu/;
,然后再进行
拆分
。这对下一个程序员来说是一件非常残酷的事情,他必须考虑到这一点。你正在寻找一台30吨重的挖掘机,而一把手铲就可以完成任务。我有点不同意:我在匹配线条s从
cpu\d*
开始,然后在列表中添加以下所有数字(推到数组上)。当然,您必须理解语法的作用。诚然,我没有检查正则表达式的性能。原始代码尝试将
cpu 35;
之后的数字作为数组收集;您只需将其作为标量添加即可。总结所有解决方案(我自己的除外)到目前为止:似乎您不能只使用一个正则表达式;相反,您必须使用两步过程(如匹配,然后拆分)。
while (<$fh>) {
    if (my ($cpu, @vals) = map { split } /^cpu([0-9]*) \s+ (.*)/x) { 
        print "$cpu $#vals\n";
    }
}
use v5.10;

while( <DATA> ) {
    next unless /\A cpu(\d*) \s /ax;
    my $cpu = $1;
    my @values = / \b (\d+) \b /agx;
    say "$cpu " . @values;
    }

__END__
cpu  2709779 13999 551920 11622773 135610 0 194680 0 0 0
cpu0 677679 3082 124900 11507188 134042 0 164081 0 0 0
cpu1 775182 3866 147044 38910 135 0 15026 0 0 0
cpu2 704411 3024 143057 37674 1272 0 8403 0 0 0
cpu3 552506 4025 136918 38999 160 0 7169 0 0 0
intr 176332106  ...
#!/usr/bin/perl
use strict;
use warnings;

my $file = "/proc/stat";
open(my $fh, "<", $file) or die "$file: $!\n";
while (<$fh>) 
{
  if ( /^cpu(\d+)(\s+)?(.*)$/ ) 
  {
    my $cpu = $1; 
    my $vals = scalar split( /\s+/, $3 ) ;
    print "$cpu $vals\n";
  }
}
close($fh);