由于未知错误,嵌套括号的动态正则表达式失败

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了由于未知错误,嵌套括号的动态正则表达式失败相关的知识,希望对你有一定的参考价值。

当我在perl中使用动态正则表达式来嵌套括号匹配时,我遇到了一个奇怪的错误。原始字符串是“{... {{}} ...}”,我想用测试grep the pair brace begain,“test {...}”。实际上这组之前可能有很多对支撑,我真的不知道它们的深度。

以下是我的匹配脚本:nesting_parser.pl

#! /usr/bin/env perl
use Getopt::Long;
use Data::Dumper;
my %args = @ARGV;

if(exists$args{'-help'})   {printhelp();}
unless  ($args{'-file'})   {printhelp();}
unless  ($args{'-regex'})  {printhelp();}

my $OpenParents;
my $counts;
my $NestedGuts = qr {
(?{$OpenParents = 0})
  (?>
    (?:
      [^{}]+
| { (?{$OpenParents++;$counts++; print "
Left:".$OpenParents." ;"})

| } (?(?{$OpenParents ne 0; $counts++}) (?{$OpenParents--;print "Right: ".$OpenParents." ;"})) (?(?{$OpenParents eq 0}) (?!))
       )*
       )
}x;


my $string  = `cat $args{'-file'}`;
my $partten =      $args{'-regex'} ;

print "####################################################
";
print "Grep [$partten{...}] from $args{'-file'}
";
print "####################################################
";


while ($string =~ /($partten$NestedGuts)/xmgs){
 print $1."}
";
  print $2."####
";
}
print "Regex has seen $counts brackts
";
sub printhelp{
print "Usage:
";
print "	./nesting_parser.pl -file [file] -regex '[regex expression]'
";
print "	[file]   : file path
";
print "	[regex]  : regex string
";
exit;
}

其实我的正则表达式是:

our $OpenParents;
our $NestedGuts = qr {
(?{$OpenParents = 0})
(?>
(?:
[^{}]+
| { (?{$OpenParents++;})
| } (?(?{$OpenParents ne 0}) (?{$OpenParents--})) (?(?{$OpenParents eq 0} (?!))
)*
)
}x;

我在nesting_parser.pl中添加了大括号计数

我还为debug编写了一个字符串生成器:gen_nesting.pl

#! /usr/bin/env perl
use strict;
my $buffer = "{{{test{";

unless ($ARGV[0]) {print "Please specify the nest pair number!
"; exit}

for (1..$ARGV[0]){
    $buffer.= "
{{{{$_}}}}";
   #$buffer.= "
{{{{{{{{{$_}}}}}}}}}";
 }
$buffer .= "
}}}}";

open TEXT, ">log_$ARGV[0]";
print TEXT $buffer;
close TEXT;

您可以通过生成测试文件

./gen_nesting.pl 1000

它将创建一个名为log_1000的日志文件,其中包含1000行支撑对

现在我们测试我们的匹配脚本:

./nesting_parser.pl -file log_1000 -regex "test" > debug_1000

debug_1000看起来是一个非常完美的结果,匹配成功!但是,当我生成4000行测试日志文件并再次匹配时,它似乎崩溃了:

./gen_nesting.pl 4000
./nesting_parser.pl -file log_4000 -regex "test" > debug_4000

debug_4000的结尾显示

{{{{3277}
####
Regex has seen 26213 brackts

我不知道正则表达式有什么问题,大多数它适用于成对的括号,直到最近我发现它在我尝试匹配超过600,000行的文本文件时崩溃了。

我真的很困惑这个问题,我真的希望能解决这个问题。

谢谢你们!

答案

首先匹配嵌套括号我通常使用Regexp::Common

接下来,我猜你的问题是Perl的正则表达式引擎在匹配32767组之后中断了。您可以通过打开警告并查找Complex regular subexpression recursion limit (32766) exceeded等消息来验证这一点。

如果是这样,你可以使用/gG以及pos重写你的代码。这个想法是你匹配循环中的括号,就像这个未经测试的代码:

my $start = pos($string);
my $open_brackets = 0;
my $failed;
while (0 < $open_brackets or $start == pos($string)) {
    if ($string =~ m/G[^{}]*({|})/g) {
        if ($1 eq '{') {
            $open_brackets++;
        }
        else {
            $open_brackets--;
        }
    }
    else {
        $failed = 1;
        break; # WE FAILED TO MATCH
    }
}
if (not $failed and 0 == $open_brackets) {
    my $matched = substr($string, $start, pos($string));
}

以上是关于由于未知错误,嵌套括号的动态正则表达式失败的主要内容,如果未能解决你的问题,请参考以下文章

python中的正则表达式嵌套括号

用于匹配嵌套括号内的特定文本的 C# 正则表达式

嵌套捕获组如何在正则表达式中编号?

删除(嵌套)括号的正则表达式

asp.net 使用正则表达式验证包含打开/关闭括号片段的属性字符串

使用正则表达式在嵌套括号外查找匹配项