Динамическое регулярное выражение для вложенных скобок не выполнено из-за неизвестных ошибок - PullRequest
0 голосов
/ 28 ноября 2018

недавно я столкнулся со странной ошибкой при использовании динамических регулярных выражений в perl для совпадения в скобках.Исходная строка: "{... test {...} ...}", я хочу получить пару скобок, начинающихся с test, "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 "\nLeft:".$OpenParents." ;"})

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


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

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


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

На самом деле мое регулярное выражение:

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

Я добавил счетчик скобок в nesting_parser.pl

Я также пишу генератор строк для отладки: gen_nesting.pl

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

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

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

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 строк.

Я действительно смущен этими проблемами, я действительно надеюсь, чторешить эту проблему.

спасибо всем!

1 Ответ

0 голосов
/ 29 ноября 2018

Сначала для сопоставления вложенных скобок я обычно использую Regexp::Common.

Далее, я предполагаю, что ваша проблема в том, что механизм регулярных выражений Perl не работает после сопоставления 32767 групп.Вы можете убедиться в этом, включив предупреждения и посмотрев сообщение типа Complex regular subexpression recursion limit (32766) exceeded.

Если это так, вы можете переписать свой код, используя /g и \G и 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));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...