Почему. * Не использует всю строку в этом регулярном выражении Perl? - PullRequest
11 голосов
/ 24 августа 2009

Почему первый оператор print не выдает то, что я ожидаю:

first = This is a test string, sec = This is a test string 

Поскольку оба * и + являются жадными, почему внутренний *, т. Е. Внутри "((" в первом совпадении, не потребляет всю строку?

use strict;
use warnings;

my $string = "This is a test string";
$string =~ /((.*)*)/; 
print "first = $1, sec = $2\n";  #prints "first = This is a test string, sec ="

$string =~ /((.+)*)/;
print "first = $1, sec = $2\n";  #prints "first = This is a test string, sec = This is a test string"

Ответы [ 4 ]

17 голосов
/ 24 августа 2009

В первом регулярном выражении .* сопоставляется два раза. Первый раз это соответствует всей строке. Во второй раз он совпадает с пустой строкой в ​​конце, потому что .* соответствует пустой строке, когда нечего сопоставлять.

Этого не происходит с другим регулярным выражением, поскольку .+ не может соответствовать пустой строке.

Редактировать: Что происходит, где: $ 2 будет содержать то, что сопоставляется в последний раз .* / .+. $ 1 будет содержать то, что соответствует (.*)* / (.+)*, то есть всей строке.

14 голосов
/ 24 августа 2009

Запуск с «use re 'debug'» приводит к:

Compiling REx "((.*)*)"
Final program:
   1: OPEN1 (3)
   3:   CURLYX[0] {0,32767} (12)
   5:     OPEN2 (7)
   7:       STAR (9) # <====
   8:         REG_ANY (0)
   9:     CLOSE2 (11)
  11:   WHILEM[1/1] (0)
  12:   NOTHING (13)
  13: CLOSE1 (15)
  15: END (0)
minlen 0 

Matching REx "((.*)*)" against "This is a test string"
   0 <> <This is a >         |  1:OPEN1(3)
   0 <> <This is a >         |  3:CURLYX[0] {0,32767}(12)
   0 <> <This is a >         | 11:  WHILEM[1/1](0)
                                    whilem: matched 0 out of 0..32767
   0 <> <This is a >         |  5:    OPEN2(7)
   0 <> <This is a >         |  7:    STAR(9) # <====
                                      REG_ANY can match 21 times out of 2147483647...
  21 < test string> <>       |  9:      CLOSE2(11)
  21 < test string> <>       | 11:      WHILEM[1/1](0)
                                        whilem: matched 1 out of 0..32767
  21 < test string> <>       |  5:        OPEN2(7)
  21 < test string> <>       |  7:        STAR(9) # <====

  # This is where the outputs really start to diverge
  # --------------------------------------------------------------------------------------------
                                          REG_ANY can match 0 times out of 2147483647...
  21 < test string> <>       |  9:          CLOSE2(11) # <==== Succeeded
  21 < test string> <>       | 11:          WHILEM[1/1](0)
                                            whilem: matched 2 out of 0..32767
                                            whilem: empty match detected, trying continuation...
  # --------------------------------------------------------------------------------------------

  21 < test string> <>       | 12:            NOTHING(13)
  21 < test string> <>       | 13:            CLOSE1(15)
  21 < test string> <>       | 15:            END(0)
Match successful!

Compiling REx "((.+)*)"
Final program:
   1: OPEN1 (3)
   3:   CURLYX[0] {0,32767} (12)
   5:     OPEN2 (7)
   7:       PLUS (9) # <====
   8:         REG_ANY (0)
   9:     CLOSE2 (11)
  11:   WHILEM[1/1] (0)
  12:   NOTHING (13)
  13: CLOSE1 (15)
  15: END (0)
minlen 0 

Matching REx "((.+)*)" against "This is a test string"
   0 <> <This is a >         |  1:OPEN1(3)
   0 <> <This is a >         |  3:CURLYX[0] {0,32767}(12)
   0 <> <This is a >         | 11:  WHILEM[1/1](0)
                                    whilem: matched 0 out of 0..32767
   0 <> <This is a >         |  5:    OPEN2(7)
   0 <> <This is a >         |  7:    PLUS(9) # <====
                                      REG_ANY can match 21 times out of 2147483647...
  21 < test string> <>       |  9:      CLOSE2(11)
  21 < test string> <>       | 11:      WHILEM[1/1](0)
                                        whilem: matched 1 out of 0..32767
  21 < test string> <>       |  5:        OPEN2(7)
  21 < test string> <>       |  7:        PLUS(9) # <====

  # This is where the outputs really start to diverge
  # ------------------------------------------------------------------------------------
                                          REG_ANY can match 0 times out of 2147483647...
                                          failed... # <==== Failed
                                        whilem: failed, trying continuation...
  # ------------------------------------------------------------------------------------

  21 < test string> <>       | 12:        NOTHING(13)
  21 < test string> <>       | 13:        CLOSE1(15)
  21 < test string> <>       | 15:        END(0)
Match successful!
3 голосов
/ 24 августа 2009

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

Первые два примера ведут себя точно так, как я ожидал: .* потребляет всю строку, а регулярное выражение возвращает список только с одним элементом. Но третье регулярное выражение возвращает список из 2 элементов.

use strict;
use warnings;
use Data::Dumper;

$_ = "foo";
print Dumper( [ /^(.*)/g ] ); # ('foo')     As expected.
print Dumper( [ /.(.*)/g ] ); # ('oo')      As expected.
print Dumper( [ /(.*)/g  ] ); # ('foo', '') Why?

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

Обновление после полезных комментариев от Час. Owens . При первой оценке любого из трех примеров .* соответствует всей строке. Если бы мы могли вмешаться и вызвать pos() в этот момент, двигатель действительно был бы в конце строки (по крайней мере, когда мы воспринимаем строку; см. Комментарии Chas. Для более полного понимания этого). Однако опция /g указывает Perl попытаться снова сопоставить регулярное выражение whole . Эта вторая попытка потерпит неудачу в примерах № 1 и № 2, и этот сбой приведет к остановке двигателя. Однако с помощью регулярного выражения # 3 движок получит другое совпадение: пустую строку. Затем опция /g говорит движку попробовать еще раз весь шаблон. Теперь действительно нечего сопоставлять - ни обычные символы, ни завершающая пустая строка - поэтому процесс останавливается.

3 голосов
/ 24 августа 2009

Проблема с первым регулярным выражением состоит в том, что ()* сохраняет только последнее совпадение, а .* соответствует пустой строке (т.е. ничего). Итак, учитывая

"aaab" =~ /(.)*/;

$1 будет "b". Если вы объедините это поведение с тем фактом, что .* соответствует пустой строке, вы увидите, что есть два соответствия внутреннего захвата: «Это тестовая строка» и «». Поскольку пустая строка пришла последней, она сохраняется в $2. $1 - это весь захват, поэтому он эквивалентен "This is a test string" . "". Второй случай работает так, как вы ожидаете, потому что .+ не будет соответствовать пустой строке.

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