Это сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

UTF-8: быстрые регулярные выражения в PHP

Утром я написал пост о производительности различных движков регулярных выражений, а весь день перебирал разные варианты, смотрел подробности и так далее.

Как я уже писал, мне понравилась библиотека RE2, я даже скомпилировал её и посмотрел, к сожалению, оказалось, что она использует треды, а в PHP с этим не очень (не все модули PHP thread safe, поэтому чаще всего PHP собирается без поддержки тредов).

Я уже начал смотреть другие библиотеки, когда Алексей Захлестин напомнил мне про модуль PHP Multibyte String (функции mb_*), который содержит в себе движок регулярных выражений Oniguruma.

Я всегда плохо относился к этому движку, так как считал, что у него очень бедные возможности для работы с UTF-8, так как там не работают \p, \P и есть ещё пара недостатков (возможно они имеют место из-за того, что в PHP используется версия 4.7.1, тогда как последняя 5.9.2).

Сегодня я присмотрелся к движку получше. Конечно, PCRE он не заменит, но некоторых случаях вполне сможет его подменить как быстрый аналог, только надо применять несколько правил (речь идёт о версии 4.7.1, которая в PHP):

Во-первых, модификатор „i“ не действует ни на какие буквы, кроме латинских, я перебрал весь Unicode, чтобы в этом убедиться.

Во-вторых, \b и \B внутри […] относятся к backspace, а не к word boundary, а \h и \H к hex digit, а не к horizontal whitespace.

В-третьих, не работают \p и \P, зато (хоть какая-то замена) с UTF-8 работают :…: (всякие там :space: и прочие).

В-четвёртых, есть синтаксис [a-w&&[^c-g]z], то есть «&» надо экранировать внутри диапазонов.

В-пятых, части синтаксиса PCRE просто нет, например, нет рекурсии, условных регулярок, но тут уже надо обращаться к документации.

Я погонял тесты, сравнивал PCRE в режиме полном UTF-8 (с «глаголом» UCP) и Oniguruma, по результатам последний в 4…4,5 раза быстрее:

bolk-dev ~/regexp-benchmark $ php test.php
PCRE Full UTF-8: 1.0458080768585
Oniguruma:         0.24942803382874
12 комментариев
Alex Crown 2010

Кстати, да. Я когда-то тоже переводил wackowiki на utf-8 и обнаружил, что не смотря на свою непопулярность и рассказы о том, что ereg медленее preg, mb_ereg оказался достаточно шустрым и с нормальной поддержкой utf (по крайней мере для wacko-форматтера).

Евгений Степанищев (bolknote.ru) 2010

Комментарий для Alex Crown:

о не смотря на свою непопулярность и рассказы о том, что ereg медленее preg

ereg действительно медленее preg, всё верно.

ereg — это библиотека POSIX regular expression
preg — это библиотека PCRE
mb_ereg — это библиотека Oniguruma

Я когда-то тоже переводил wackowiki на utf-8

А есть какой-то рассказ на эту тему?

Alex Crown (alex@alexcrown.net) 2010

Комментарий для Евгения Степанищева:

А есть какой-то рассказ на эту тему?

В конце 2007 я увлёкся идеей wiki, начал пользоваться wackowiki и в процессе эксплуатации понял, что мне очень не хватает поддержки юникода. Сейчас уже не помню, почему, но думаю, что считал поддержку юникода жизненно важной фичей. Начал исправлять и втянулся.
Реализовал поддержку юникода с помощью расширения mbstring и mb_ereg, перенёс работу с БД на AdoDb, переписал всё в ООП стиле, локализацию переделал на gettext. В общем, учился программировать на PHP.

Потом меня обнаружили ребята, которые сейчас занимаются проектом http://sourceforge.net/projects/wackowiki/ и предложили делать 5 версию на основе мой модификации. Но я слишком увлёкся рефакторингом и не смог довести проект до релиза. Интерес к проекту угас и он так и остался лежать в папке незавершенных. Может быть когда-нибудь я к нему вернусь...

Кстати, помнится, что я связывался с Костей Коломейцом с предложением отдать wackowiki под GPL или сотрудничать, но он в начале 2008 года говорил, что Яндекс сам уже к лету 2008 выпустит версию с utf8 и прочими плюшками. Видимо это тоже повлияло на решение не продолжать проект.

nudnik.ru 2010

Комментарий для Alex Crown (alex@alexcrown.net):

Так вот ты какое, лето 2008-ого.

Alex Crown 2010

Что-то после твоего поста на меня нашло и я полночи пытался извлечь репозиторий из бекапов и конвертировать его в hg. Сам не знаю зачем :)

Залил сюда https://bitbucket.org/alexcrown/kex

Где-то в районе 107 ревизии я решил делать форк, назвал его kex, переименовал все классы и забросил проект.

Евгений Степанищев (bolknote.ru) 2010

Комментарий для Alex Crown:

:))
Напиши статью на «Хабре», глядишь подхватят проект.

jimidini (indeyets.ru) 2010

а я его сейчас ради интереса соберу с новой онигурумой. посмотрю как оно

jimidini (indeyets.ru) 2010

Комментарий для indeyets.ru:

ага. с новой онигурумой твой тест из прошлой записи выдаёт 1/1/1/1 и ни одного false

jimidini (indeyets.ru) 2010

А ещё не забывай про  http://docs.php.net/mb_regex_set_options

Евгений Степанищев (bolknote.ru) 2010

Комментарий для indeyets.ru:

Ага, спасибо!

Виктор 2011

Подскажите пожалуйста, перенес wackowiki 4.2 с дебиана на фрю и урлы http://blalala.org/wiki/%D0%98%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F превратились в  http://blalala.org/wiki/Izmenenija?v=39t​. При этом если исправить в строке на  http://blalala.org/wiki/%D0%98%D0%B7%D0%BC%D0%B5%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F?v=39t  — работает, а если в конце код стереть — предлагает создать новую страницу. У wackowiki 5 c русскими урлами всё в порядке.
Подскажите куда копать?
Благодарю!

Виктор 2011

Блин... прошу прощения, получились несуществующие спам ссылки )