![]() |
|
Модераторы: ginnie |
![]()
|
|
| reekoff |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 13 Регистрация: 23.12.2011 Репутация: нет Всего: нет |
Привет! Читаю книжку Фридла. Там выражение. Не могу вкурить результаты его работы.
Без ? в конструкции (44\d\d\d) оно захватывает в массив фрагменты из 5-ти цифр начинающиеся с 44, а заодно, в конце строки из-за смещения поиска забирает неверный фрагмент 44712. Там написано, что если добавить ? к (44\d\d\d), то выражение работать не будет. Пытаюсь разобраться. Оно вроде и работает (находит нужные 2 фрагмента), но совершенно не понятно определяет их в массив. $_ = '012342345644567345675678944789123458765447120'; @zips = m/(?:\d\d\d\d\d)*?(44\d\d\d)?/g; print $zips[3], " and ", $zips[7], " and ", @zips,"\n"; результат: 44567 and 44789 and 4456744789 Получается, что совпадают 2 фрагмента и пишутся в 4-й и 8-й элементы массива. Не могу понять, почему именно так происходит. Я считал, что выражение совпадет сразу в первой позиции (перед нулем), ибо необязательны обе конструкции ()*? и ()?, и в $zips[0] будет пустое значение. Затем из-за /g произойдет смена позиции поиска в строке и выражение совпадет в позиции перед 1 (в $zips[1] пустое значение). И так далее, пока поиск не дойдет до 44567 которые совпадут с (44\d\d\d)?. Но эта подстрока, по-моему, должна была сохраниться в $zips[10]??? И далее, тем же макаром, 44789 в zips[21] и 44712 в zips[31]. На деле же, смещение происходит не так как я думал. Кто-нибудь может объяснить работу этого выражения? Спасибо! |
|||
|
||||
| Pfailed |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 933 Регистрация: 19.7.2009 Репутация: 6 Всего: 39 |
Работает вторая версия примерно так:
"(?:\d\d\d\d\d)*?" - выражение со знаком вопроса вконце, а значит не жадное. "*" значит 0 и более раз и если бы выражение было бы жадным (без знака вопроса), то всё началось бы с попытки найти это выражение (5 цифр) 1 раз вначале строки. Но оно нежадно, а значит производится попытка найти это выражение 0 раз вначале строки. Найти что-либо где-либо 0 раз не составляет труда и значит этот этап заканчивается успехом. "(44\d\d\d)?" - знак вопроса вконце в данном случае означает 0 или 1 раз, но это выражение жадное, т.е. сначала производится проверка на совпадение 1 раз. Мы по прежнему вначале строки и совпадения здесь не находится, пробуется второй вариант - 0 раз. Опять успех. Итак на этом этапе первое и второе выражение совпали 0 раз вначале строки. В первую захватывающую скобку попадает undef. Далее первое выражение не может совпасть 0 раз вначале строки, такое уже было на предыдущем шаге, пробуется альтернативый вариант - совпасть 1 раз. И оно совпадает. Второе выражение вновь не может совпасть в этой позиции (6-я цифра в строке "2") 1 раз. Но опять совпадает 0 раз. Успех. В захватывающей скобке вновь undef. Теперь мы в позиции 6 и здесь первое выражение еще не совпадало 0 раз. Пробуем. Совпадает. Второе выражение. 1 раз - неудача. 0 раз - успех. В захватывающей скобке undef. Теперь первое выражение должно совпасть 1 раз в позиции 6. Оно совпадает. Мы оказываемся в позиции 11 и наконец то второе выражение совпало 1 раз. В захватывающую скобку попадает "44567". Итого на этом этапе @zips = (undef, undef, undef, 44567) Далее по аналогии. Для разбора регулярных выражений весьма полезно бывает добавить в начало скрипта use re 'debug' или use re 'debugcolor'. |
|||
|
||||
| reekoff |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 13 Регистрация: 23.12.2011 Репутация: нет Всего: нет |
Хмм, все складно вроде.
Но, может объясните... Вот у нас все выражение совпало в позиции перед первым нулем, в первом элементе массива undef, успех совпадения всего выражения в текущей позиции. Почему же опять начинается поиск в той же самой позиции (перед нулем)? Разве /g не должно продолжать поиск в строке дальше, с позиции после найденного совпадения? Ведь (?:\d\d\d\d\d)*? уже отработало не жадный вариант и совпало. Нет смысла прорабатывать в этой же позиции жадный вариант, не прав? Я понимаю, что нескладухи у меня в голове, что-то упускаю в правилах. |
|||
|
||||
| Pfailed |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 933 Регистрация: 19.7.2009 Репутация: 6 Всего: 39 |
В нашем случае найденное совпадение имеет нулевую длину, а это значит, что позиция после найденного совпадения остаётся там же. Например "1" =~ /(^|1)/g; Сначала находится начало строки - выражение с нулевой длиной. А что дальше? Сдвигать позицию и продолжать поиск после 1? Нет. Курсор остаётся в начале строки и на следующей итерации совпадает с единицей, т.к. знает, что начало строки уже совпадало. |
|||
|
||||
| reekoff |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 13 Регистрация: 23.12.2011 Репутация: нет Всего: нет |
Pfailed, спасибо тебе.
А что можно почитать для того, чтобы вывод re debug перестал сводить с ума? |
|||
|
||||
| Pfailed |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 933 Регистрация: 19.7.2009 Репутация: 6 Всего: 39 |
Возможно "perldoc re" поможет, но вообще это дело времени.
|
|||
|
||||
![]()
|
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Perl: Регулярные выражения | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |