Получение нескольких совпадений в строке с помощью регулярных выражений в Perl

Прочитав этот похожий вопрос и попробовав мой код несколько раз, я продолжаю получать один и тот же нежелательный вывод.

Давайте предположим, что строка, которую я ищу, это "Я видел Вильму вчера". Регулярное выражение должно содержать каждое слово, за которым следует "а" и его необязательные 5 следующих символов или пробелов.

Код, который я написал, выглядит следующим образом:

$_ = "I saw wilma yesterday";

if (@m = /(\w+)a(.{5,})?/g){
    print "found " . @m . " matches\n";

    foreach(@m){
        print "\t\"$_\"\n";
    }
}

Тем не менее, я продолжал получать следующий вывод:

found 2 matches
    "s"
    "w wilma yesterday"

в то время как я ожидал получить следующее:

found 3 matches:
    "saw wil"
    "wilma yest"
    "yesterday"

пока я не узнал, что возвращаемые значения внутри @m мы $1 а также $2, как вы можете заметить.

Теперь, так как /g флаг включен, и я не думаю, что проблема в регулярном выражении, как я могу получить желаемый результат?

3 ответа

Решение

Вы можете попробовать этот шаблон, который позволяет перекрывать результаты:

(?=\b(\w+a.{1,5}))

или же

(?=(?i)\b([a-z]+a.{0,5}))

пример:

use strict;
my $str = "I saw wilma yesterday";
my @matches = ($str =~ /(?=\b([a-z]+a.{0,5}))/gi);
print join("\n", @matches),"\n";

больше объяснений:

Вы не можете иметь перекрывающиеся результаты с регулярным выражением, так как, когда персонаж "съеден" механизмом регулярных выражений, он не может быть съеден во второй раз. Уловка, чтобы избежать этого ограничения, состоит в том, чтобы использовать заглядывание (то есть инструмент, который только проверяет, но не совпадает), которое может пройти через строку несколько раз, и поместить группу захвата внутрь.

Для другого примера этого поведения, вы можете попробовать пример кода без границы слова (\b) чтобы увидеть результат.

Во-первых, вы хотите захватить все внутри выражения, то есть:

/(\w+a(?:.{5,})?)/

Затем вы хотите начать поиск с одного символа, за которым совпадал первый символ последнего выражения.

pos() Функция позволяет указать, где /g регулярное выражение начинает свой поиск с.

$s = "I saw wilma yesterday";    
while ($s =~ /(\w+a(.{0,5}))/g){
    print "\t\"$1\"\n";
    pos($s) = pos($s) - length($2); 
}

Дает тебе:

"saw wil"
"wilma yest"
"yesterday"

Но я не знаю, почему вы должны получить day и не yesterday,

Другие вопросы по тегам