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
22 декабря 2010 20:43

Alex Crown (инкогнито)
22 декабря 2010, 23:08

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

bolk (bolknote.ru)
22 декабря 2010, 23:20, ответ предназначен Alex Crown

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

ereg — это библиотека POSIX regular expression
preg — это библиотека PCRE
mb_ereg — это библиотека Oniguruma
Я когда-то тоже переводил wackowiki на utf-8
А есть какой-то рассказ на эту тему?

Alex Crown (alex@alexcrown.net) (инкогнито)
23 декабря 2010, 00:50, ответ предназначен bolk (bolknote.ru):

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

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

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

nudnik.ru (nudnik.ru)
23 декабря 2010, 02:53, ответ предназначен Alex Crown (alex@alexcrown.net)

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

Alex Crown (инкогнито)
23 декабря 2010, 11:34

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

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

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

bolk (bolknote.ru)
23 декабря 2010, 13:25, ответ предназначен Alex Crown

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

jimidini (indeyets.ru)
23 декабря 2010, 16:28

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

jimidini (indeyets.ru)
23 декабря 2010, 16:32

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

jimidini (indeyets.ru)
23 декабря 2010, 16:49

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

bolk (bolknote.ru)
23 декабря 2010, 18:17, ответ предназначен jimidini (indeyets.ru):

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

Виктор (инкогнито)
16 марта 2011, 14:24

Подскажите пожалуйста, перенес wackowiki 4.2 с дебиана на фрю и урлы http://blalala.org/wiki/Изменения превратились в http://blalala.org/wiki/Izmenenija?v=39t. При этом если исправить в строке на http://blalala.org/wiki/Изменения?v=39t - работает, а если в конце код стереть - предлагает создать новую страницу. У wackowiki 5 c русскими урлами всё в порядке.
Подскажите куда копать?
Благодарю!

Виктор (инкогнито)
16 марта 2011, 14:26

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

Ваше имя или адрес блога (можно OpenID):

Текст вашего комментария, не HTML:

Кому бы вы хотели ответить (или кликните на его аватару)