用于捕获重复组的Perl正则表达式

5ssjco0h  于 2022-11-15  发布在  Perl
关注(0)|答案(5)|浏览(151)

我需要一个正则表达式,它匹配一行开头的某个单词,然后匹配(并返回)所有其他单词。例如,给定下面这行:

$line = "one two three etc";

我想要这样的东西(不工作):

@matches= $line=~ /^one(?:\s+(\S+))$/;

为了返回到@匹配,单词“two”、“three”、“etc”。
我不想知道如何得到单词。我想用一个正则表达式来做。它看起来很简单,但我一直没有能想出一个解决方案。

5lhxktic

5lhxktic1#

要做到这一点,你需要使用\G锚来匹配最后一个匹配的结尾位置。当你用这个锚点构建一个模式时,你可以获得连续的结果:

@matches = $line =~ /(?:\G(?!\A)|^one) (\S+)/g;
wixjitnu

wixjitnu2#

捕获组的数目不能未知。如果尝试重复捕获组,则最后一个示例将覆盖捕获组的内容:

或者:

我建议捕获整个组,然后按空格拆分:

或者,您可以执行全局匹配并利用\G\K

drkbr07n

drkbr07n3#

^.*?\s\K|(\w+)

试试这个。看演示。
http://regex101.com/r/lS5tT3/2

9ceoxa92

9ceoxa924#

(?{...})“执行代码”特殊分组可用于记忆必要的中间分组捕获
让我们从您的代码开始:

#!/usr/bin/perl

$line = "one two three etc";
@matches = ();
$line=~ /^one(?:\s+(\S+)(?{push @matches, $1}))+$/;
print join "\n", @matches;

@matches数组中包含“two”、“three“等。因为在部分匹配后执行的(?{push @matches,$1})会将捕获的值存储在这里。
更复杂的例子可以更好地阐明这种方法:

#!/usr/bin/perl

while(<>) { $a .= $_; }
$a =~ m{cipher-suites:\s*\[[\r\n" ]+(?:([^\]]*?)[\r\n", ]+(?{push @r, $1}))+\]}sm;

print join "\n", @r;
__END__
cipher-suites: [
  "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
  "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
  "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
  "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
  "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384",
  "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"
]

这会将密码提取到数组@r中
(?{...})“execute code”是一个非常强大的正则表达式扩展,例如,它可以扩展正则表达式,使其可以匹配嵌套的括号表达式。

klr1opcd

klr1opcd5#

最简单的解决办法可能是事后对split

use strict;
use warnings;

my $line = "one two three etc";

my @matches = $line =~ /^one\s+(.*)/ ? split(' ', $1) : ();

use Data::Dump;
dd @matches;

输出:

("two", "three", "etc")

但是,也可以使用\G从上一个匹配中断的地方继续,从而使用/g修饰符找到所有非空格。
唯一的技巧是记住不要让\G在字符串的开头匹配,这样单词one就必须匹配:

my @matches = $line =~ /(?:^one|(?<!\A)\G)\s+(\S+)/g;

相关问题