我如何使完全不捕获的任意Perl正则表达式? (回答:您不能)

问题描述 投票:8回答:6

如何从Perl正则表达式字符串中任意嵌套的子组中删除捕获?我想将任何正则表达式嵌套到一个包围表达式中,该表达式将子正则表达式捕获为一个整体以及静态已知的后续组。我是否需要手动将正则表达式字符串转换为使用所有未捕获的(?:)组(并希望我不要搞乱),或者是否有提供此功能的Perl正则表达式或库机制?

# How do I 'flatten' $regex to protect $2 and $3?
# Searching 'ABCfooDE' for 'foo' OK, but '((B|(C))fo(o)?(?:D|d)?)', etc., breaks.
# I.E., how would I turn it effectively into '(?:(?:B|(?:C))fo(?:o)?(?:D|d)?)'?
sub check {
  my($line, $regex) = @_;
  if ($line =~ /(^.*)($regex)(.*$)/) {
    print "<", $1, "><", $2, "><", $3, ">\n";
  }
}

附录:我隐约知道$&$`$',并建议尽量避免使用它们,而且我无权访问${^PREMATCH}${^MATCH}${^POSTMATCH}在我的Perl 5.8环境中。可以使用上述方法将上面的示例划分为2/3块,更复杂的实际情况可以手动进行迭代,但是我认为,如果可能,我希望有一个通用的解决方案。

[Accepted Answer:

我希望存在,但令人惊讶的是(至少对我而言)没有,这是一个使内容不透明的封装组,因此后续的位置反向引用将内容视为单个实体,而名称引用是范围外的gbacon对于Perl 5.10+具有潜在的有用解决方法,FM显示了针对任何版本的手动迭代机制,可以在特定情况下实现相同的效果,但是j_random_hacker称没有真正的语言机制可以封装子表达式。

如何从Perl正则表达式字符串中任意嵌套的子组中删除捕获?我想将任何正则表达式嵌套到一个包围表达式中,该表达式也将子正则表达式捕获为一个整体实体...

regex perl
6个回答
8
投票

一般来说,不能。


7
投票

保护您关心的子模式的一种方法是使用named capture buffers


5
投票

[这不能解决一般情况,但是您可以在标量上下文中使用/g选项来处理您的特定示例,这将使您将问题分为两个匹配项,第二个从第一个中断的地方开始:] >

sub check {
    my($line, $regex) = @_;
    my ($left_side, $regex_match) = ($1, $2) if $line =~ /(^.*)($regex)/g;
    my $right_side = $1 if $line =~ /(.*$)/g;
    print "<$left_side> <$regex_match> <$right_side>\n"; # <AB> <CfooD> <E123>
}

check( 'ABCfooDE123', qr/((B|(C))fo(o)?(?:D|d)?)/ );

2
投票

如果您只需要匹配前后的字符串部分,则可以使用@-@+数组将偏移量获取到匹配的字符串中:

sub check {
    my ($line, $regex) = @_;
    if ($line =~ /$regex/) {
        my $pre   = substr $line, 0, $-[0];
        my $match = substr $line, $-[0], $+[0] - $-[0];
        my $post  = substr $line, $+[0];
        print "<$pre><$match><$post>\n";
    }
}

2
投票

Perl v5.22和更高版本具有/n修饰符,可关闭所有捕获。


0
投票

这不会禁用捕获,但是可能会完成您想要的操作:

$ perl -wle 'my $_ = "123abc"; /(\d+)/ && print "num: $1"; { /([a-z]+)/ && print "letter: $1"; } print "num: $1";'
num: 123
letter: abc
num: 123
© www.soinside.com 2019 - 2024. All rights reserved.