Извлечение слов между началом и концом, \ G \ K - PullRequest
3 голосов
/ 29 марта 2020

Этот шаблон работает

(?:\G(?!\A)|begin).*?\K(keyword)(?=.*end)

Строка:

begin
keyword
keyword 
end

Я получаю то, что хочу (ключевое слово) только в одной группе захвата, но если строка имеет это:

begin
keyword
keyword 
end
keyword
end

Я получаю три матча, Как остановиться в первом end?

Может ли этот шаблон быть лучше, оптимизирован?

demo regex

Ответы [ 3 ]

2 голосов
/ 29 марта 2020

Я бы не хотел сталкиваться с таким регулярным выражением в коде. Любое небольшое изменение, и оно сломано.

Я бы открыл файловый дескриптор на ссылку на строку, а затем прочитал ее строки. Пропускайте все, пока не попадете в начальную строку, а затем прочитайте все до конечной строки:

use v5.26;

my $string =<<~'HERE';
    begin
    keyworda
    keywordb
    end
    keywordc
    end
    HERE

open my $fh, '<', \$string;

while( <$fh> ) { last if /\Abegin/ }

my @keywords;
while( <$fh> ) {
    last if /^end/;
    chomp;
    push @keywords, $_;
    }

say join "\n", @keywords;

Это приводит к выводу:

keyworda
keywordb

Или разбейте его на два регулярных выражения. Один устанавливает начальную позицию, затем вы несколько раз совпадаете, пока линия не является конечной. Это немного чище, но некоторые люди могут быть смущены глобальным соответствием в скалярном контексте:

use v5.26;

my $string =<<~'HERE';
    begin
    keyworda
    keywordb
    end
    keywordc
    end
    HERE

my @keywords;
if( $string =~ / ^ begin \R /gmx ) {
    while( $string =~ /\G (?!end \R) (\N+) \R /gx ) {
        push @keywords, $1;
        }
    }

say join "\n", @keywords;
0 голосов
/ 30 марта 2020

Вы можете использовать not equal в группировке для извлечения данных из begin в end.

 my @keyws = ($data=~/begin((?:(?!begin|end).)*)end/sg);

 use Data::Dumper;

 print Dumper @keyws;

Это мой способ сделать в LaTeX.

0 голосов
/ 30 марта 2020

Используйте регулярные выражения и сохраняйте совпадения в массиве

my @result = $data =~ /begin\n(.*?)\nend/sg;

, затем выводите на консоль

use strict;
use warnings;
use feature 'say';

use Data::Dumper;

my $data = do { local $/; <DATA> };

my @result = $data =~ /begin\n(.*?)\nend/sg;

say '-' x 35 . "\n" . $_ for @result;

__DATA__
begin
keyword 1
keyword 2
end
keyword
end
keyword
begin
keyword 3
keyword 4
end
keyword 
keyword 

Вывод

-----------------------------------
keyword 1
keyword 2
-----------------------------------
keyword 3
keyword 4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...