Как я могу извлечь строку между двумя символами + сделать это рекурсивно? - PullRequest
0 голосов
/ 11 ноября 2009

У меня есть строка:

123 + FOO1[ccc + e_FOO1 + ddd + FOO2[b_FOO2]] = 123

Теперь мне нужно проверить, что FOO1 отображается вместе с e_. То есть не может быть такой ситуации:

123 + FOO1[ccc + e_FOK1 ...]

Мой простой вопрос: как я могу сказать Perl, чтобы он перехватил слово FOO1, например?

Я думал, что искать между 2 символами: " " и "["

, а затем проверьте правильность написания после " e_", например, между "[..]".

КАК МОЖНО СДЕЛАТЬ ЭТО РЕКУРСИВНО?

Ответы [ 4 ]

2 голосов
/ 11 ноября 2009

Вам необходимо написать синтаксический анализатор для вашего мини-языка: См. Parse :: RecDescent . Калькулятор демо будет хорошей отправной точкой.

#!/usr/bin/perl

use strict;
use warnings;

my ($expr) = @ARGV;

my @tokens = split //, $expr;

my ($word, $inside) = (q{}, 0);

for my $token (@tokens) {
    $token =~ /\A\w\z/ and do { $word .= $token; next };

    if ( $inside ) {
        if ( $word =~ /FOO1/ ) {
            $word eq 'e_FOO1'
                or die "No FOO1 w/o e_ prefix allowed!\n"
        }
    }
    else {
        $word !~ /FOO1/
            or die "No FOO1 allowed!\n";
    }

    $token eq '[' and ++$inside;
    $token eq ']' and --$inside;
    $word = '';
}
C:\Temp> t.pl "123 + MOO1[ccc + e_FOO1 + ddd + FOO2[b_FOO2]] = 123"
C:\Temp> t.pl "123 + FOO1[ccc + e_FOO1 + ddd + FOO2[b_FOO2]] = 123"
No FOO1 allowed!
C:\Temp> t.pl "123 + MOO1[ccc + FOO1 + ddd + FOO2[b_FOO2]] = 123"
No FOO1 w/o e_ prefix allowed!

См. Также FAQ Можно ли использовать регулярные выражения Perl для сопоставления сбалансированного текста?

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

Основываясь на некоторых ваших комментариях, я собираюсь предположить, что ваш вопрос "заключен в квадратные скобки" ["и"], убедитесь, что любой символ "e_" - это "e_FOO", а не что-то другое ...

(Изменить: хорошо, похоже, вам нужно, чтобы ключевое слово "FOO" также появлялось непосредственно перед квадратными скобками. Я соответствующим образом пересмотрю регулярное выражение.)

if ($line =~ /
              ([A-Z]+)  # match a keyword in all caps, and save it for later
                        # (we can retrieve it with \1 or $1)
              \[        # match the first [
                [\]]*   # some number of any character that isn't ]
                e_      # a ha, here's our e_
                \1      # and here's our keyword that we matched earlier
                [\]]*   # some more of any character that isn't ]
              \]        # here's our closing ]
             /x)
{
     say "Good data";
}
else
{
     say "Bad data";
}

Но, пожалуйста, начните читать некоторые уроки в perldoc perlre .

0 голосов
/ 11 ноября 2009

поскольку вы сказали: «Мне нужно подтвердить, что за FOO1 следует строка« e_ », заключенная в скобки», вам просто нужно проверить e_FOO1, верно? нет необходимости в слишком сложном регулярном выражении.

my $str="123 + FOO1[ccc + e_FOO1 + ddd + FOO2[b_FOO2]] = 123";
my $s = index($str,"[");
my $e = index($str,"]");
my $f = index($str,"e_FOO1");
if ( $f >=$s and $f <= $e ){
    print "found \n";
}
0 голосов
/ 11 ноября 2009

Если ваша ситуация сложнее, чем вы описали, этот код не будет работать (например, он ничего не делает для обеспечения баланса между левыми и правыми скобками). Тем не менее, код иллюстрирует, как использовать обратные ссылки (см. \1 ниже), что может привести вас на правильный путь.

use strict;
use warnings;

while (<DATA>){
    warn "Bad line: $_" unless / (\w+) \[ .* e_\1 .* \] /x;
}

__DATA__
123 + FOO1[ccc + e_FOO1 + ddd + FOO2[b_FOO2]] = 123
123 + FOO1[ccc + e_FOOx + ddd + FOO2[b_FOO2]] = 123
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...