Получение нескольких совпадений в строке с помощью регулярных выражений в 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
,