Что значит .*?на самом деле означает регулярное выражение? - PullRequest
2 голосов
/ 23 марта 2011

Я использую Perl уже десять лет. Но в последнее время я запутался с использованием. *? регулярное выражение.

Кажется, оно не соответствует минимальному количеству символов. Иногда это дает разные результаты.

Например, для этой строки: aaaaaaaaaaaaaaaaaaaaaammmmmmmmmmbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab и pattern: a. *? B соответствует полной входной строке в двух группах Согласно определению это должно было соответствовать последнему «ab».

Ответы [ 6 ]

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

Пример сокращен до:

'aaab' =~ /a.*?b/

Что происходит:

  1. a соответствует a.
  2. .*? соответствует наименьшему числувозможно символов (0), соответствует пустой строке.
  3. b не соответствует.⇒ возврат
  4. .*? соответствует наименьшему возможному количеству символов (1), совпадение a
  5. b не соответствует.⇒ возврат
  6. .*? соответствует наименьшему возможному количеству символов (2), соответствует aa
  7. b соответствует b.
  8. Соответствие шаблона успешно.

Я стараюсь избегать не жадного модификатора.

'aaab' =~ /a[^a]*b/

Если a действительно что-то более сложное, то можно использовать отрицательный взгляд.

'aaab' =~ /a(?:(?!a).)*b/
6 голосов
/ 23 марта 2011

Это означает

.   # match any character except newlines
*   # zero or more times
?   # matching as few characters as possible

Таким образом, в

<tag> text </tag> more text <tag> even more text </tag>

регулярное выражение <tag>(.*)</tag> будет соответствовать всей строке сразу, захватывая

 text </tag> more text <tag> even more text 

в обратной ссылкечисло 1.

Если вы сопоставите это с <tag>(.*?)</tag>, вы получите два совпадения:

  1. <tag> text </tag>
  2. <tag> even more text </tag>

только с text и even more text, захваченными в обратной ссылке № 1, соответственно.

И если (спасибо Коби!), Ваш исходный текст будет

<tag> text <tag> nested text </tag> back to first level </tag>

тогда вы обнаружите, что <tag>(.*)</tag> снова соответствует всей строке, но <tag>(.*?)</tag> будет соответствовать

<tag> text <tag> nested text </tag>

, потому что механизм регулярных выражений работает слева направо.Это одна из причин, по которой регулярные выражения являются «не лучшим инструментом» для сопоставления контекстно-свободных грамматик.

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

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

1 голос
/ 23 марта 2011

Я не думаю, что вы можете напрямую сопоставить ab в вашем случае. Часто, когда .*? не работает, он вызывает шаблон [^c]*, где c - символ или класс символов. Это предотвращает ложноположительные совпадения

В этом случае, однако, это не работает: a[^a]*b соответствует ammmmmmmmmmmb в первую очередь. Таким образом, единственный способ найти самое короткое совпадение - это найти все совпадения, а затем выбрать самое короткое.

Ниже приведен подробный (вы сказали, что некоторое время не работал с Perl; -) способ достижения желаемого результата:

#!/usr/bin/perl 

use strict;
use warnings;

use List::Util qw(reduce); # see List::Util docs for what reduce does

my $s= "aaaaaaaaaaaaaaaaaaaaaaammmmmmmmmmmbaaaaaaaaaaaaaaaaaaaaaab";

my $RE= qr/a[^a]*b/;

print "regexp: $RE\n";                 # ammmmmmmmmmmb
print "single match:\n";
if( $s=~ m{($RE)}) { print "  $1\n"; } 

print "all matches (loop):\n";         # ammmmmmmmmmmb \n ab
while( $s=~ m{($RE)}g)
  { print "  - $1\n"; }

print "all matches (in an array):\n";  # ammmmmmmmmmmb - ab
my @matches= $s=~ m{(a[^a]*b)}g;
if( @matches) { print "  ", join( " - ", @matches), "\n"; }

print "\nshortest match: ";            # ab
print reduce { length $a < length $b ? $a : $b } @matches;
print "\n";

Короче говоря, ленивое соответствие - это не то же самое, что получить самое короткое соответствие в строке. И получить это самое короткое соответствие - непростая проблема с тем типом движка rexegp, который используется в Perl (и я полагаю, что большинство других языков).

1 голос
/ 23 марта 2011

Предполагается, что оно соответствует минимальному количеству символов, необходимому для успешного совпадения шаблона в целом (если совпадение вообще существует). Можете ли вы привести конкретный пример, где он этого не делает?

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

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

Вы используете правильную конструкцию, поэтому, возможно, проблема в остальной части вашего запроса. У меня тоже были проблемы с этим, но я всегда понимал, что это произошло из-за моего желаемого анализа - то есть, я хотел бы, чтобы регулярные выражения анализировали то, что я имел в виду, а не то, как я набирал:

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