Почему мое регулярное выражение Perl вызывает бесконечный цикл?

У меня есть код, который захватывает «между» некоторым текстом; в частности, между foo $someword и следующим foo $someword.

Однако происходит то, что он застревает на первом «между» и каким-то образом внутренняя позиция строки не увеличивается.

Входные данные представляют собой текстовый файл с новыми строками здесь и там: они не имеют значения, но облегчают печать.

my $component = qr'foo (\w+?)\s*?{';

while($text =~ /$component/sg)
{
    push @baz, $1; #grab the $someword
}

my $list = join( "|", @baz);
my $re = qr/$list/; #create a list of $somewords

#Try to grab everything between the foo $somewords; 
# or if there's no $foo someword, grab what's left.

while($text=~/($re)(.+?)foo ($re|\z|\Z)/ms)   
#if I take out s, it doesn't repeat, but nothing gets grabbed.
{
#   print pos($text), "\n";   #this is undef...that's a clue I'm certain.
    print $1, ":", $2; #prints the someword and what was grabbed.
    print "\n", '-' x 20, "\n";
}

person Paul Nathan    schedule 18.08.2009    source источник
comment
Вам не нужен модификатор /g и во втором цикле?   -  person jrockway    schedule 19.08.2009
comment
\z и \Z не обязательны, \Z содержит \z   -  person Chas. Owens    schedule 19.08.2009
comment
Я иду по тексту, не захватывая массив (это то, что /g вернет). Однако /g не влияет на проблему конечного вывода. Я пробовал. :-)   -  person Paul Nathan    schedule 19.08.2009
comment
@chas: изменение его на \Z и добавление \g приводит к тому, что он зацикливается один раз. Удаление \g приводит к бесконечному циклу.   -  person Paul Nathan    schedule 19.08.2009


Ответы (1)


Обновление. Еще одно обновление для устранения 'foo' внутри текста, который вы хотите извлечь:

use strict;
use warnings;

use File::Slurp;

my $text = read_file \*DATA;

my $marker = 'foo';
my $marker_re = qr/$marker\s+\w+\s*?{/;

while ( $text =~ /$marker_re(.+?)($marker_re|\Z)/gs ) {
    print "---\n$1\n";
    pos $text -= length $2;
}

__DATA__
foo one {
one1
one2
one3

foo two
{ two1 two2
two3 two4 }

that was the second one

foo three { 3
foo 3 foo 3
foo 3
foo foo

foo four{}

Вывод:

---

one1
one2
one3


---
 two1 two2
two3 two4 }

that was the second one


---
 3
foo 3 foo 3
foo 3
foo foo


---
}
person Sinan Ünür    schedule 18.08.2009
comment
О, да. Я ищу все после { и до следующего foo. - person Paul Nathan; 19.08.2009
comment
Это работает. Без pos $text -= 3 он возвращает первое и последнее. Боюсь, я совершенно не понимаю, почему ваше решение сработало, а что не так с моим. Мысли? - person Paul Nathan; 19.08.2009
comment
Поиск (?:foo|\Z) продвигает pos $text на длину foo, если есть foo. Таким образом, следующее совпадение начинается после следующего foo, если только pos $text не сбрасывается в положение перед следующим foo, которое находится за три символа до текущей позиции. Если вы уже достигли конца строки, это не имеет значения. - person Sinan Ünür; 19.08.2009
comment
@Sinan: я заметил, что если есть мой $foomatic, регулярное выражение соответствует «foo». Я изменил свое регулярное выражение, чтобы иметь \bfoo\b. :-) Большое спасибо за помощь. - person Paul Nathan; 19.08.2009