Ребята, привет всем! Подскажите, пожалуйста, следующее: Текст для обработки: Вопрос: возможно ли использование backreference в первом аргументе pattern функции preg_replace() (http://ru2.php.net/manual/en/function.preg-replace.php)? Код (Text): $tmp = preg_replace("/\\t(.+?)\\{$1=(ADV|CONJ)\\b.+?\\}/i", "\t$1($2)", $input); Здесь bacreference $1 используется в первом параметре. На практике вижу, что, похоже, так нельзя. Так как в сети пока подтверждения не нашел, решил спросить у знатоков.
Все равно не цепляет по регэкспу... Код (Text): <?php if( isset( $_FILES["qwe"] ) ) { $dictext = file_get_contents($_FILES["qwe"]["tmp_name"], FILE_TEXT); if( ! empty($dictext) ) { $tmp_ = $dictext; $tmp_ = preg_replace('/(?<=\\t)(.+?)\\{.*?\\1=(A|ADV|CONJ)\\b[^{]+?\\}/', "$1($2)", $tmp_); echo $tmp_; } } else { echo "Не указан файл!"; } ?>
Mr.M.I.T., спасибо за помощь! Но все же и этот вариант не прокатывает. Код (Text): if( isset( $_FILES["qwe"] ) ) { $dictext = file_get_contents($_FILES["qwe"]["tmp_name"], FILE_TEXT); if( ! empty($dictext) ) { $text = "above{above} поверх{поверх=ADV=|поверх=PR=}"; $text = preg_replace("#(?<=\t|^)(.+?){(\\1(?:=(A|ADV|CONJ)=)?\|?)+}#","\\1(\\3)", $text); echo $text; // вывод: "above() поверх{поверх=ADV=|поверх=PR=}" } Главное узнал, что bacreference возможен в pattern для preg_replace! Я вообще пользую конструктор RegexBuddy для отладки регулярных выражений (http://www.regexbuddy.com/), проверял в этот раз и другими конструкторами (напр. http://www.pcre.ru/eval/). Все работало согласно задумке, но в php какая-то заминка...
Похоже, что изначальная проблема с которой я начал описание в теме, связана с исходным файлом, загружаемым на парсинг. Если задаю текст для обработки в файле .php, то все ок, если загрузка из файла (пробовал и с utf-8 файлом и с ansi - результат тот же), скрипт не выводит ничего...
Короче, не хочу забегать вперед, но, кажется, приближаюсь к разгадке. Загружаемый текстовый файл довольно крупный (~1,5 Мб) с большим количеством разнообразного текста. Похоже, preg_replace спотыкается на каком-то фрагменте в файле (возвращает NULL), в итоге скрипт выдавал пустышку. Сейчас урезал файл до первых нескольких строк - все нормально, пропарсилось! Осталось разобраться в чем же на самом деле была проблема. Как найду в чем было дело, опишусь Кстати, вопрос к знатокам: в каких случаях preg_replace может вернуть NULL? ru2.php.net отписались лишь вскользь:
Ну у меня вообще-то pcre.recursion_limit и pcre.backtrack_limit были закомментированы в php.ini. Раскомментировал, поставил лимиты в 900 000, запустил скрипт, он подгрузил процессор на 50%, но так за минуту ни до чего и не додумался. В обрабатываемом файле знаков с пробелами: 897 243. Также напрягают вот такие комментарии: Мдаа.. непонятно чо делать. Наверное стоит кусками файлы читать.
Что я могу посоветовать. Простая регулярка кушает и 10мб файл при стандартном pcre.backtrack_limit = 100000 Если тестируешь локально - то увеличивай на сколько сможешь. (10/20/100млн) только память выдели для PHP соответственно. Там не только число знаков в строке важно, а сколько вариантов конечных автоматов может построится строится как я понимаю. Т.е. для большого текста и скажем (.*)+ это число очень быстро растет в геометрической прогрессии. Попробуй переделать регулярку на более конкретный поиск. P.S. Настройки рекурсии, кстати пока лучше не трогай, ты только ухудшаешь себе задачу.
Согласен, большое спасибо за помощь! Да я бы рад уточнить, сам не люблю всяких .* .+ и прочего, одни проблемы начинаются, но в файле чего только нет. Видимо, придется кусками обрабатывать. Подумаю, конечно, еще, что можно уточнить в регулярке. Еще раз спасибо всем!
Короче, ребята, все получилось с Perl. С вышеуказанной регуляркой и текстовым файлом объема 1,5 Мб скрипт выполнился за менее чем три секунды! Вчера до трех утра сидел никак не мог скурить почему и в Perl не работает. Сегодня догадался - указал в явном виде кодировку и все! Код (Text): use locale; use POSIX; &POSIX::setlocale(&POSIX::LC_ALL, "Russian_Russia.866");