Модераторы: ginnie
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Не понятна работа регэкспа 
:(
    Опции темы
reekoff
Дата 23.12.2011, 10:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 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]. 
На деле же, смещение происходит не так как я думал.
Кто-нибудь может объяснить работу этого выражения?
Спасибо!

PM MAIL   Вверх
Pfailed
Дата 23.12.2011, 11:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 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'.



--------------------
PM MAIL   Вверх
reekoff
Дата 23.12.2011, 11:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 23.12.2011

Репутация: нет
Всего: нет



Хмм, все складно вроде.
Но, может объясните...
Вот у нас все выражение совпало в позиции перед первым нулем, в первом элементе массива undef, успех совпадения всего выражения в текущей позиции.
Почему же опять начинается поиск в той же самой позиции (перед нулем)? Разве /g не должно продолжать поиск в строке дальше, с позиции после найденного совпадения? Ведь (?:\d\d\d\d\d)*? уже отработало не жадный вариант и совпало. Нет смысла прорабатывать в этой же позиции жадный вариант, не прав?
Я понимаю, что нескладухи у меня в голове, что-то упускаю в правилах.  smile 
PM MAIL   Вверх
Pfailed
Дата 23.12.2011, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 6
Всего: 39



Цитата(reekoff @  23.12.2011,  11:58 Найти цитируемый пост)
Разве /g не должно продолжать поиск в строке дальше, с позиции после найденного совпадения?

В нашем случае найденное совпадение имеет нулевую длину, а это значит, что позиция после найденного совпадения остаётся там же.

Например "1" =~ /(^|1)/g;
Сначала находится начало строки - выражение с нулевой длиной. А что дальше? Сдвигать позицию и продолжать поиск после 1? Нет. Курсор остаётся в начале строки и на следующей итерации совпадает с единицей, т.к. знает, что начало строки уже совпадало.



--------------------
PM MAIL   Вверх
reekoff
Дата 23.12.2011, 14:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 13
Регистрация: 23.12.2011

Репутация: нет
Всего: нет



Pfailed,  спасибо тебе.
А что можно почитать для того, чтобы вывод re debug перестал сводить с ума?
PM MAIL   Вверх
Pfailed
Дата 23.12.2011, 21:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 933
Регистрация: 19.7.2009

Репутация: 6
Всего: 39



Возможно "perldoc re" поможет, но вообще это дело времени.


--------------------
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: Регулярные выражения | Следующая тема »


 




[ Время генерации скрипта: 0.0541 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.