我想要一个正则表达式,它可以匹配一行开头的内容并匹配(并返回)所有其他单词。例如,给出以下这行内容:
$line = "one two three etc";
我想要像这样的东西(但它不起作用):
我希望获得类似以下内容的效果(但是无法实现):
@matches= $line=~ /^one(?:\s+(\S+))$/;
为了返回@matches中的单词 "two"、"three" 等,我想使用正则表达式来解决,不想知道如何获取这些单词。
这似乎很简单,但我一直没有找到解决方案。
\G
锚点,该锚点匹配上次匹配结束的位置。当您使用此锚点构建模式时,可以获得连续的结果:@matches = $line =~ /(?:\G(?!\A)|^one) (\S+)/g;
^one(?:\s+(\S+))+$
捕获 #1: etc
^one\s+(\S+)\s+(\S+)\s+(\S+)$
捕获 #1: two
捕获 #2: three
捕获 #3: etc
我建议先捕捉整个字符串,然后按空格分割:
^one\s+((?:\S+\s*)+)$
two three etc
或者您可以进行全局匹配,并利用\G
和\K
:
(?:^one|(?<!\A)\G).*?\K\S+
two
three
etc
/(?:^one|(?<!\A)\G).*?(\K\S+)/g
。 - agarrubio\K
是不是必要的?但它有用吗? - agarrubio\K
会丢弃左侧匹配的所有内容,因此无需捕获\S+
,因为它是唯一剩下的匹配内容。 - Sam$line="anything two three etc"
。 - agarrubio(?{...}) "执行代码" 特殊分组可以用于记忆必要的中间分组捕获
让我们从你的代码开始:
#!/usr/bin/perl
$line = "one two three etc";
@matches = ();
$line=~ /^one(?:\s+(\S+)(?{push @matches, $1}))+$/;
print join "\n", @matches;
@matches数组中将包含“two”,“three”,“etc”等内容。因为在部分匹配后执行(?{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中。
(? {...})“执行代码”是一种非常强大的正则表达式扩展,例如可以通过匹配嵌套括号表达式扩展正则表达式。
最简单的解决方案可能是事后分割
:
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;
two three etc
,定义 3 个捕获组,或者对每个词进行全局匹配并将其分别放入捕获组1中。 - Sam