![]() |
|
Модераторы: ginnie |
![]()
|
|
| MasterOfRegex |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 17 Регистрация: 25.10.2010 Репутация: нет Всего: нет |
print "Match: \$1=$1" if 'abcde' =~ /^((\w\w+)(?{print defined $2 ? "-$2-\n" : "--\n"})){2}$/;
Выводит: -abcde- -- -- -de- Match: $1=de Объясните, почему 2 раза $2 оказался undefined, ведь после выхода за 2-ю захватывающую скобку в $2 должно быть минимум 2 символа. Сергей Статьи по Perl регулярным выражениям |
|||
|
||||
| alezzz |
|
|||
![]() сплю... ![]() ![]() Профиль Группа: Участник Сообщений: 499 Регистрация: 17.8.2009 Репутация: 11 Всего: 14 |
Не претендую на гениальность, но мысль такая:
Нужно получить из выражения (\w\w+) и еще раз (\w\w+). Первый проход для первого (\w\w+), захватили "a", далее для \w+ захватили "b" и все до конка строки, т.е. "bcde", все выражение попадает в $2. Далее нужно найти второй (\w\w+). Начинаются возвраты. Первый возврат: получили \w, второй возврат: получили \w+ в количистве 1-ого символа, т.к. достаточно. Так вот, там где $2 undef -- это, видимо, и есть 2 возврата. print "Match: \$1=$1" if 'abcdef' =~ /^((\w\w{2,})(?{print defined $2 ? "-$2-\n" : "--\n"})){2}$/; тут нужно 3 возврата, выводит: -abcdef- -- -- -- -def- Match: $1=def |
|||
|
||||
| MasterOfRegex |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 17 Регистрация: 25.10.2010 Репутация: нет Всего: нет |
Здесь наличие возвратов не должно играть роли, т.к. 2-я пара скобок, по логике, всегда участвует в совпадении и что-то захватывает. Классики учили, что в этом случае после закрытия скобки формируются переменные $2, $+ и $^N, а также обратная ссылка \2. Здесь всё это имеет неопред. значение, как будто 2-я пара скобок не участвовала в совпадении.
\w можно убрать, оставив только \w+, e из строки тоже можно убрать: #!perl -w use strict; use re qw(debug); print "Match: \$1=$1 \$2=$2" if 'abcd' =~ /^((\w+) (?{print defined $2 ? "\$2=$2\n" : "\$2 not defined\n"}) ){2}$ /x; Если вставить use re qw(debug); то выведется это re на псевдокоде и его работа, из которой видно, что вторая пара скобок закрывается, когда текущая позиция в строке находится в её конце... Как же в этом случае можно идти дальше за скобку, непонятно... Это похоже на какую-то ошибку... Попробую написать на [email protected]. Сергей === cd тоже можно убрать: #!perl -w use strict; use re qw(debug); print "Match: \$1=$1 \$2=$2" if 'ab' =~ /^((\w+) (?{print defined $2 ? "\$2=$2\n" : "\$2 not defined\n"}) ){2}$ /x; Выводит: $2=ab $2 not defined $2=b Match: $1=b $2=b Хм, вроде я понял, ошибок тут, похоже, нет, зря гуру с [email protected] беспокоил... Undefined выводится, когда предыдущий захват 2-й парой скобок откачен, а нового захвата ещё не было. Хотя в re мы находимся за 2-й парой скобок. Вот так ставить квантификаторы к захватывающим скобкам... ;-\ Это сообщение отредактировал(а) MasterOfRegex - 17.2.2011, 11:37 |
|||
|
||||
| alezzz |
|
||||
![]() сплю... ![]() ![]() Профиль Группа: Участник Сообщений: 499 Регистрация: 17.8.2009 Репутация: 11 Всего: 14 |
Ну а я что сказал?!
Все правильно, один возврат для второго \w+, один undef Якорь $ можно убрать, \w+ захватывает до конца строки. Это сообщение отредактировал(а) alezzz - 17.2.2011, 14:06 |
||||
|
|||||
| MasterOfRegex |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 17 Регистрация: 25.10.2010 Репутация: нет Всего: нет |
Да и ^ тоже можно убрать.
Я над этим серьёзно ещё не думал, а сейчас подумал раза 2 и считаю, что это всё-таки ошибка. Поспешил я со 2-м письмом в perl.org, ладно, посмотрим, что завтра-послезавтра оттуда ответят. Вот мой разбор работы этого re, как я понимаю этот механизм. Итак, имеем: 'ab' =~ /((\w+)(?{print defined $2 ? "\$2=$2\n" : "\$2 not defined\n"})){2}/; Оно выводит: $2=ab $2 not defined $2=b Проблема: почему $2 not defined? Ведь мы визуально только что перед этим выводом закрыли 2-ю скобку и должны получить $2 (а также $+, $^N и \2 определёнными, т.к. 2-я пара скобок только что участвовала в совпадении. А они все неопределённые. Что-то не то... Я подозреваю, что возможная ошибка возникла от того, что нумерованные переменные (и вообще спец. переменные re) локализуются не только при входе в каждый блок программы (т.е. имеют структуру стека)), но и внутри re, а это неправильно. При об-ке этого re оно должно как бы раскручиваться: аналогично тому, как \w{2} эквивалентно \w\w, так и всё re эквивалентно ((\w+)({print ...})((\w+)({print ...}) Но при этом во 2-м экз. скобки нумеруются тоже 1 и 2 и порождают $1 и $2. Вначале 1-е \w+ захватит всё ab и на печать выйдет $2=ab. Затем входим во 2-й экз. re и когда входим во 2-1 экз. 2-й скобки, $2 получает значение undefined. Видим, что \w не совпадает. Не беда, у нас есть сохр. состояние, возвращаемся к 1-му экз. 2-й скобки. Но при возврате мы входим справа в 1-й экз. 2-й пары скобок, поэтому $2 опять получает значение undefined, которое наслаивается на предыдущее, а это неправильно. Квантификатор + отдаёт 1 букву, мы захватываем 1-м экз. 2-й пары скобок символ a, затем выходим за скобку. Тут надо сформировать $2 и т.д., но, видимо, здесь механизм об-ки re видит, что $2 уже имеет значение, поэтому вместо этого отменяется предыдущее значение undefined для $2, в результате $2 опять получает значение undefined, что и выводится, а надо вывести a. Вот так мне кажется... === Я ещё поумал и вижу, что я ошибался: когда \w+ отдаёт символ b, то мы не заходим левее открывающей скобки в выражении (\w+), поэтому $2 остаётся неопределённым, что и печатается. === Опа, я через неск. часов после этого опять раза 2 подумал и пришёл к выводу, что $2=undefined интуитивно должно быть ошибочно, правильно всё-таки выводить $2=a, как я раньше писал. Проверил почту - вот это да, пришёл ответ от гуру рег. выражений Дж. Фридла, который живёт на regex.info. (В сети есть 3-е издание его книги "Регулярные выражения"). Он написал: Hi Serge, I've been thinking about this for a while, and as far as I can tell it does seem to be a bug. By definition, $2 must be defined before the (?{...}) can run. It's probably a problem with how it backtracks. I'd suggest filing a bug report.. Поначалу я раздвоил это выражение ввиду квантификатора {2}, получилось такое: ((\w+)(?{print...}))((\w+)(?{print...})) (Здесь имеем в виду, что вторая копия также производит $1 и $2). Но так рассуждать неправильно, реально ничего не раздваивается. Вот почему выводится $2=undefined, по моему мнению: вначале (\w+) захватывает всё и выводится, что $2=ab. Далее выходим на модификатор {2}. Текущая позиция отмечена через |: (\w+)) | {2} Видим, что повтор \w не совпадает. Делаем бэктрекинг и по пути входим справа за закрывающую скобку: (\w+ | ) Видимо, в этом случае движок делает $2 undefined, а почему? Интуитивно кажется, что это надо делать только, когда мы выходим левее соответствующей открывающей скобки. Но я сомневаюсь, что авторы движка станут это исправлять: это вопрос идеологии работы движка, и ведь тогда теоретически некоторые старые программы могут начать не так работать... Это сообщение отредактировал(а) MasterOfRegex - 19.2.2011, 18:12 |
|||
|
||||
| MasterOfRegex |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 17 Регистрация: 25.10.2010 Репутация: нет Всего: нет |
Народ, который занимается разработкой Перла, окончательно признал, что "This *is* a bug. An optimization bug probably. In the PLUS regop." И вот интересный пример такого человека, который написал вышеприведённые слова: заменим \w+ на (?:\w|z)+ и потом на (?:\w|zz)+, получим разный вывод:
'ab' =~ /(((?:\w|z)+)(?{print defined $2 ? "\$2=$2\n" : "\$2 not defined\n"})){2}/; $2=ab $2 not defined $2=b 'ab' =~ /(((?:\w|zz)+)(?{print defined $2 ? "\$2=$2\n" : "\$2 not defined\n"})){2}/; $2=ab $2=a $2=b Кстати, я на днях засабмитил ещё один багрепорт, связанный с неправильной работой операторов \L, \l, \U и \u. Эти операторы, в отличие от функций lc, lcfirst, uc и ucfirst, выполняются слева направо: print "\L\udD\n"; # Dd верно print "\LdD\udD\n"; # dddd уже неверно! А если рядом поставить \U и \L (4 комбинации), то вообще будет кошмар: ошибка синтаксиса: print "\U\La\n"; Сергей (www.cronc.com/ru.shtml) |
|||
|
||||
![]()
|
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Perl: Регулярные выражения | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |