Как я могу использовать Perl для проверки этих данных, содержащих сбалансированный текст? - PullRequest
2 голосов
/ 18 ноября 2009

У меня есть текстовый файл, заполненный предложениями с уникальным рисунком. Уникальный шаблон:

NAME [ e_NAME ]

простое правило: после «e_» должно следовать «NAME», если внутри скобок появляется «e_»

Проблема возникает, когда строка сложная. Я покажу конечные ситуации, которые трудно проанализировать:

Линии, которые не соответствуют правилу:

(1) NAME1[blabla+NAME2[blabla+e_BAD2]+e_NAME1]
(2) NAME1[blabla] + NAME2[e_BAD2]
(3) NAME1[NAME2[blabla+e_BAD2]] + NAME3[e_BAD3]
(4) NAME1[e_NAME1BAD1] -> means it has to be only NAME1

Строки, соответствующие правилу:

(1) FOO1[blabla + 1]
(2) [blalbla] + bla
(3) bla + blabla
(4) FOO1[ccc + ddd + FOO2[e_FOO2]] = 123
(5) FOO1[cc + FOO2[ dd ] ] + FOO3[e_FOO3]

Я уже задавал этот вопрос , но я не смог уловить эти конечные точки ...

Ответы [ 4 ]

1 голос
/ 19 ноября 2009
use Text::Balanced;

CPAN - это прекрасно.

1 голос
/ 18 ноября 2009

На основании принятого ответа на ваш первый вопрос я придумал:

use strict;
use warnings;

while (<DATA>) {
   my $l = $_;
   while (s/(\w+)\[([^\[\]]*)\]//) {
      my ($n, $chk) = ($1, $2);
      unless ($chk =~ /\be_$n\b/) {
         warn "Bad line: $l";
         last;
      }
   }
}

\b проверяет границы слова. Эта версия по-прежнему не проверяет наличие несбалансированных скобок, но, похоже, она улавливает все примеры, которые вы привели, и также будет жаловаться, когда e_NAME1 находится внутри другого вложенного блока, например:

NAME1[stuff + NAME2[e_NAME1 + e_NAME2] + morestuff]
1 голос
/ 19 ноября 2009

Отредактировано после уточнения требований

Может быть полезным либо Text :: Balanced , либо Regexp :: Common . Сначала я опубликовал ответ, используя первый, но он мне не очень понравился. В следующем примере используется Regexp::Common и кажется довольно простым.

use strict;
use warnings;
use Regexp::Common;

my $PRE   = '[^[]*?';
my $VAR   = '\w+';
my $BRACK = $RE{balanced}{-parens=>'[]'};
my $POST  = '.*';

while (<DATA>){
    my ($bad, $full);

    # Brackets, if any, must balance
    $bad = 1 unless s/\[/[/g == s/\]/]/g;

    $full = $_;
    until ($bad){
        # Find some bracketed text and store all components.
        my ($pre, $var, $brack, $post) =
            $full =~ /^($PRE)($VAR)($BRACK)($POST)$/;
        last unless defined $brack;

        # Create a copy of the bracketed text, removing both the outer
        # brackets and all instances of inner-bracketed text.
        chop (my $clean = substr $brack, 1);
        $clean =~ s/$BRACK/ /g;

        # If e_FOO exists, FOO must equal $var.
        $bad = 1 if $clean =~ /e_(\w+)/ and $1 ne $var;

        # Remove the part of $full we've already checked.
        substr($full, 0, length($pre) + length($var) + 1, '');
    }

    print if $bad;
}

# Your test data, with some trailing comments.    
__DATA__
NAME1[blabla+NAME2[blabla+e_BAD2]+e_NAME1]               NOT OK 1
NAME1[blabla] + NAME2[e_BAD2]                            NOT OK 2
NAME1[NAME2[blabla+e_BAD2]] + NAME3[e_BAD3]              NOT OK 3
NAME1[e_NAME1BAD1]                                       NOT OK 4
FOO1[blabla + 1]                                         OK 1
[blalbla] + bla                                          OK 2
bla + blabla                                             OK 3
FOO1[ccc + ddd + FOO2[e_FOO2]] = 123                     OK 4
FOO1[cc + FOO2[ dd ] ] + FOO3[e_FOO3]                    OK 5
1 голос
/ 18 ноября 2009

Может быть, вы ищете что-то вроде:

 if ($string =~ /(\w+)\[e\\_(\w+)/ &&  $1 eq $2) {
     print "Pattern '$1' contained in string '$string'\n";
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...