Как я могу найти самую короткую последовательность символов, которая соответствует моему шаблону регулярных выражений? - PullRequest
3 голосов
/ 23 марта 2011

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

Я хочу шаблон, который будет соответствовать последнему "ab", а не всей строке или даже "aab".

/a.*?b/  # returns two groups

или

/a.??b/ # matches last aab

Ни то, ни другое не работает.

Ответы [ 4 ]

5 голосов
/ 23 марта 2011

Один из:

/a[^a]*b/
/a[^ab]*b/

Если a и b на самом деле являются более сложными шаблонами, можно использовать следующее:

/a(?:(?!a).)*b/s
/a(?:(?!a|b).)*b/s

Если a и b представляют длинные / сложные шаблоны, можно избежать их повторения, используя переменные, как в любом другом коде.

my $re1 = qr/a/;
my $re2 = qr/b/;

/$re1(?:(?!$re1|$re2).)*$re2/s

Можно также использовать подшаблоны.

/
   (?&A) (?:(?!(?&A)|(?&B)).)* (?&B)

   (?(DEFINE)
      (?<A> a )
      (?<B> b )
   )
/xs
5 голосов
/ 23 марта 2011

Простой способ обойти вашу проблему состоит в следующем:

.*(a.*b)

Поскольку первый .* является жадным, он соответствует столько, сколько может. Затем вы получаете захваченную группу с тем матчем, который вам действительно нужен ($1). Обратите внимание, что это предполагает, что вы соответствуете последнему вхождению шаблона. Вы можете захотеть .*(a.*?b), если у вас есть несколько b s в конце строки, и вы хотите первую после последней a.

3 голосов
/ 23 марта 2011

По умолчанию для сопоставления с образцом в Perl оставлен самый длинный, самый длинный *.Использование ??, *? или +? изменит эту часть на «Самый левый», «Самый короткий», но «Самый левый» по-прежнему имеет приоритет.

Существует способ заставить Perl соответствовать «Мому правый», что можетдайте вам желаемый эффект, но это также приведет в замешательство следующего человека, который будет читать ваш код, поэтому используйте его с осторожностью.

Основная идея состоит в том, чтобы полностью изменить все, что связано с сопоставлением с образцом, поэтомустановится левым.

my $subject = 'ajjjjjjjjjaab';
my $rev_sub = reverse $subject; # reverse the string being matched.
my $result;
if ($rev_sub =~ /(b.*?a)/) {    # reverse the pattern to match.
    $result = reverse $1;       # reverse the results of the match.
}
print $result;

Решения, предоставленные ikegami и Kobi, оба находят аналогичные результаты для вашего примера.В зависимости от ваших реальных шаблонов и строк, вы можете найти очень разную производительность для каждого метода.Всегда Benchmark исходя из ваших реальных потребностей.

* Дольше только для сопоставляемого непосредственного токена, исключая чередования, которые пробуются в порядке слева направо и т. Д.

0 голосов
/ 23 марта 2011

Хорошо, но затем используйте просто /ab/ для сопоставления, и все готово.Или /a{1}b/.Или

...