Форум программистов, компьютерный форум, киберфорум
Perl
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/5: Рейтинг темы: голосов - 5, средняя оценка - 5.00
reekoff

Не понятна работа регэкспа

23.12.2011, 11:37. Показов 984. Ответов 3
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет! Читаю книжку Фридла. Там выражение. Не могу вкурить результаты его работы.

Без ? в конструкции (44\d\d\d) оно захватывает в массив фрагменты из 5-ти цифр начинающиеся с 44, а заодно, в конце строки из-за смещения поиска забирает неверный фрагмент 44712. Там написано, что если добавить ? к (44\d\d\d), то выражение работать не будет. Пытаюсь разобраться. Оно вроде и работает (находит нужные 2 фрагмента), но совершенно не понятно определяет их в массив.

Perl
1
2
3
$_ = '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].
На деле же, смещение происходит не так как я думал.
Кто-нибудь может объяснить работу этого выражения?
Спасибо!
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
23.12.2011, 11:37
Ответы с готовыми решениями:

Не понятна работа цикла for c указателями.
Помогите разобраться со следующей прогой: #include <stdio.h> void main(){ char s="Удалить пробелы и табуляции из строки"; ...

Не понятна работа конструктора копирования
Добрый день! Читаю Шилдта базовый курс. Дошел до конструктора копии.В книжных примерах вроде все понятно было. Перешел на перегрузку...

Работа функции hash_equals() не совсем понятна
Здравствуйте, друзья. Что-то я не понимаю результат работы этого кода: $salt = substr(md5(time()), 0, 7); $hashed_password =...

3
0 / 0 / 0
Регистрация: 21.01.2012
Сообщений: 3
21.01.2012, 20:04
Интересный пример. Изменил Ваш пример вот так:
Perl
1
2
3
4
$_ = '012342345644567345675678944789123458765447120';
@zips = m/(?:\d\d\d\d\d)*?(44\d\d\d)?/g;
$i = 1;
print $i++.": '$_'\n" foreach @zips;
а потом вот так:
Perl
1
2
3
4
5
$_ = '012342345644567345675678944789123458765447120';
$i = 1;
while (m/(?:\d\d\d\d\d)*?(44\d\d\d)?/g) {
    print $i++.": "."pos: ".pos()." '$1'\n";
}
Вывод один и тот же:
1: pos: 0 ''
2: pos: 5 ''
3: pos: 5 ''
4: pos: 15 '44567'
5: pos: 15 ''
6: pos: 20 ''
7: pos: 20 ''
8: pos: 30 '44789'
9: pos: 30 ''
10: pos: 35 ''
11: pos: 35 ''
12: pos: 40 ''
13: pos: 40 ''
14: pos: 45 ''
15: pos: 45 ''


Могу попытаться объянить поведение так (как на самом деле работает -- не знаю).
Имеем модификатор g в списковом контексте. Он возвращает список всех удач при поиске. Другими словами, применяем шаблон до первой удачи, запоминаем то, что в скобках, помещаем массив. Далее, снова пытаемся применить этот же шаблон, но уже с позиции pos, на котором завершился предыдущий поиск. Позиция pos смещается(изменяется) только в случае удачи.

Шаблон (?:\d\d\d\d\d)*?(44\d\d\d)? по сути является набором из 4х шаблонов, которые мы пытаеся применить в порядке приоритетов:
(?:пусто)*?(44\d\d\d)
(?:пусто)*?(пусто)
(?:\d\d\d\d\d)*?(44\d\d\d)
(?:\d\d\d\d\d)*?(пусто)
Поочерёдно пытаемся применить шаблоны. Если успех, запоминаем новую позицию pos. Если она НЕ изменилась, пытаемся применить следующий шаблон. Если же изменилась, то начинаем проверять шаблоны заново, с первого.
Смещение происходит как минимум на 5ть позиций, потому что хотя бы один из шаблонов приводит к успеху. Если бы мы проверили все шаблоны и все привели к неудаче, то произошло бы смещение на одну позицию. И мы продолжили бы попытки проверять шаблоны с самого первого.

Шаг 1:
находимся вот тут: ^01234 23456 44567 34567 56789 44789 12345 87654 47120
пытаемся применить шаблон (?:пусто)(44\d\d\d). для этого читаем 5 символов: 01234. видим, что не проходит. говорим: "Ок, зачем нам вторые скобки, если там знак вопроса?"
пытаемся применить шаблон (?:пусто)(пусто). Вуаля - годится. Чтобы применить данный шаблон, нам пришлось считать 0 символов. Значит, новое положение pos = 0.

находимся вот тут: ^01234 23456 44567 34567 56789 44789 12345 87654 47120. Положение не изменилось, продолжаем перебирать шаблоны.
нам нужно перебрать все удачные совпадения шаблона. смотрим, что первые два шаблона мы уже использовали - пытаемся использовать третий.
пытаемся применить шаблон (?:\d\d\d\d\d)*?(44\d\d\d). Позиция так же 0. Читаем 10 символов: 01234 23456. Шаблон не подходит, но мы не сдаёмся.
пытаемся применить шаблон (?:\d\d\d\d\d)*?(пусто). Читаем 5 символов: 01234. Успех. Запоминаем новое положение в pos = 5.

Шаг 2:
находимся вот тут: 01234^23456 44567 34567 56789 44789 12345 87654 47120
пытаемся применить шаблон (?:пусто)(44\d\d\d). для этого читаем 5 символов: 23456. шаблон не совпадает.
пытаемся применить шаблон (?:пусто)(пусто). И снова, внезапно пустой шаблон нам подходит. Чтобы применить данный шаблон, нам пришлось считать 0 символов. Значит, новое положение pos = 5

находимся вот тут: 01234^23456 44567 34567 56789 44789 12345 87654 47120
пытаемся применить шаблон (?:\d\d\d\d\d)*?(44\d\d\d). Читаем 10 символов: 23456 44567. Успех. Новое положение pos = 15.

находимся вот тут: 01234 23456 44567^34567 56789 44789 12345 87654 47120. Положение изменилось. Начинаем проверять шаблоны заново.

Шаг 3:
находимся вот тут: 01234 23456 44567^34567 56789 44789 12345 87654 47120. Положение изменилось. Начинаем проверять шаблоны заново.
пытаемся применить шаблон (?:пусто)(44\d\d\d). для этого читаем 5 символов: 34567. шаблон не совпадает.
пытаемся применить шаблон (?:пусто)(пусто). И снова пустой шаблон нам подходит. Чтобы применить данный шаблон, нам пришлось считать 0 символов. Значит, новое положение pos = 15. Совпадает со старым.

находимся вот тут: 01234 23456 44567^34567 56789 44789 12345 87654 47120
пытаемся применить шаблон (?:\d\d\d\d\d)*?(44\d\d\d). Читаем 10 символов: 34567 56789. Неудача.
пытаемся применить шаблон (?:\d\d\d\d\d)*?(пусто). Читаем 5 символов: 34567. Успех. Запоминаем новое положение в pos = 20. Положение изменилось, начинаем проверять шаблоны с самого начала.

Шаг 4:
...
0
Эксперт С++
 Аватар для odip
7176 / 3234 / 82
Регистрация: 17.06.2009
Сообщений: 14,164
22.01.2012, 10:29
Во-первых
In list context, a match /regex/ with groupings will return the list of matched values ($1,$2,...).

Это значит что выражение m/(?:\d\d\d\d\d)*?(44\d\d\d)?/g; на каждом проходе генерирует $1
и именно это значение записывается в @zips
При этом очевидно что $1 - это (44\d\d\d)
так как (?: ) - тут приказывается не генерировать $1

Поэтому на самом деле в массив @zips записывает не все выражение что было сопоставлено, а только часть его !
Которая причем по большей части пустая

Поэтому переделаю пример чтобы все было понятно
Perl
1
2
3
4
5
6
7
#!/usr/bin/perl
 
$_ = '012342345644567345675678944789123458765447120';
 
while ( m/((?:\d\d\d\d\d)*?(44\d\d\d)?)/g ) {
    print "pos=", pos(), " match=|$1| save=|$2|\n";
}
Вывод
Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pos=0 match=|| save=||
pos=5 match=|01234| save=||
pos=5 match=|| save=||
pos=15 match=|2345644567| save=|44567|
pos=15 match=|| save=||
pos=20 match=|34567| save=||
pos=20 match=|| save=||
pos=30 match=|5678944789| save=|44789|
pos=30 match=|| save=||
pos=35 match=|12345| save=||
pos=35 match=|| save=||
pos=40 match=|87654| save=||
pos=40 match=|| save=||
pos=45 match=|47120| save=||
pos=45 match=|| save=||
Добавлено через 1 минуту
В выводе pos - это позиция сопоставления шаблона
match - это сопоставленный шаблон полностью
save - это то что в исходном шаблоне есть $1, а в нашем шаблоне есть $2
save - это именно то что записывается в массив @zips

Добавлено через 2 минуты
Из этого примера видно что сопоставление в одной позиции происходит несколько раз
При этом из всех вариантов шаблонов пустой шаблон применяется в последнюю очередь
На самом деле если есть варианты - в первую очередь применяется более длинный шаблон
0
Эксперт С++
 Аватар для odip
7176 / 3234 / 82
Регистрация: 17.06.2009
Сообщений: 14,164
22.01.2012, 10:31
Немного изменим пример
Perl
1
2
3
4
5
6
7
#!/usr/bin/perl
 
$_ = '012342345644567345675678944789123458765447120';
 
while ( m/((?:\d\d\d\d\d)*(44\d\d\d)?)/g ) {
    print "pos=", pos(), " match=|$1| save=|$2|\n";
}
Вывод
Code
1
2
3
> perl 1.pl
pos=45 match=|012342345644567345675678944789123458765447120| save=||
pos=45 match=|| save=||
Все правильно - вот так оно и должно работать - берется цикл максимальной длины
Фактически вся строка сопоставилась с (?:\d\d\d\d\d)*

Добавление '?' в исходном regexp заставляет perl изменить стратегию перебора регулярных выражений
Сначала сопоставляется самый короткий непустой цикл
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
22.01.2012, 10:31
Помогаю со студенческими работами здесь

Не понятна конструкция
Доброго времени суток! Разбираюсь с шумом Перлина и в одном из исходников кода встретил такую конструкцию: uint64_t rdtsc() { ...

Не понятна формула
Всем привет! Мне необходимо рассчитать ценовой ряд из формул. В математике слаб. Если в картинке, что слева вроде понятно, поправьте,...

Не понятна формула
Вот в данной формуле (на фотографии) нахождения дифференциала 2-го порядка мне не понятен один момент, который я обвел красным цветом. Это...

Не понятна часть программы
Я еще учусь,поэтому прошу отнестись с пониманием. Увидела на форуме код, не поняла часть где индекс массива i больше или равен 48 и...

не понятна причина ошибки
Добрый вечер. Осваиваю куки(этим объясняется последующий жуткий код). Делаю следующее-на html страничку подключаю php файл, который...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Программа принимает математическое выражение в виде строки и выдаёт его производную в виде строки и вычисляет значение производной при заданном х Логарифм записывается как: (x-2)log(x^2+2) -. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru