Чем быстрее всего отрезать строку в кодировке UTF-8

Решил протестировать — чем быстрее всего можно отрезать строку в кодировке UTF-8. В PHP для этой цели (помимо использования извращений, типа SQL-запроса) можно использовать: mb_substr из модуля «Multibyte string function», iconv_substr из модуля iconv, preg_replace в режиме UTF-8 из Perl-Compatible regular expression function и собственную реализацию прохода по UTF-8 строке.

Я взял строку в 700 UTF-8-символов и отрезал от неё 500 разными функциями. Вот что получилось (PHP 5.2.4 без акселераторов):

  • хуже всех справилась реализация на чистом PHP — 0.34 сек
  • получше — iconv_substr. 0.063 сек
  • ещё лучше — mb_substr. 0.0175 сек
  • лучше всех — preg_replace. 0.005 сек
    Если кому интересно, вот моя функция по проходу по строке в кодировке UTF-8:
$len = strlen($text);
    for ($pos = $cutted = 0; $cutted < $cut && $pos < $len; ++$cutted)
    {
            $ch = ord($text[$pos]);

            // multibyte char
            if (0x80 & $ch)
            {
                    for (; $ch & 0x80; ++$pos, $ch <<= 1);
            }
            else
            {
                    $pos++;
            }
    }

Итак, лучший способ отрезать первые $N символов UTF-8 таков:

preg_replace('/^(.{'.$N.'}).*$/uSs', '$1', $text)

Комментарии 17

Alisey (alisey.myopenid.com) № 1
Евгений, а вот такие эксперименты, кроме того что это забавно и разница действительно огромна, имеют ли они ещё какой-то смысл для вас?
Мне кажется такие вещи вредно включать в долговременную память. Позиции могут измениться с любой новой версией языка или библиотек.

Хотел показать, только что на hackety.org натолкнулся, аналог NodeBox на Lua. I thought you might like.
http://www.4p8.com/lew/gallery.html
Евгений Степанищев (bolknote.ru) автор № 2
Для меня это текущая задача — в моём движке есть функция отрезания текста, используется она часто, я, было, сделал ветвление, в зависимости от библиотеки, которая есть, а, оказывается, это не требуется — всех делает regexp.
zencd.livejournal.com № 4
A bug report: комментарии не отдаются по рсс. Глянь например мой поток — там ошибки в пхп: https://bolknote.ru/rss/zencd.livejournal.com

А вообще комментарии по рсс это сила. Жаль всех на эту технологию на пересадишь :). Да и преобразователь уведомлений-по-емейлу в уведомления-по-рсс (для единства) непонятно как реализовать.
zencd.livejournal.com № 3
Может имеет смысл подпатчить iconv_substr? (не локально, в рамках развития проекта). Всё-таки разница в 10 раз …

И написать тестик (в рамках пхп-девелопмента же), чтобы сравнивать две реализации и если вдруг регекспы затормозят — выдать предупреждение.
Евгений Степанищев (bolknote.ru) автор № 5
Комментарий для zencd.livejournal.com:

RSS починил. Реализовать просто — робот получает e-mail, формирует RSS.
zencd.livejournal.com № 6
Комментарий для Евгения Степанищева:

Оффтоп эгейн: я смотрю тег пустой — предлагаю писать туда название статьи (если есть) — в рсс-ридере (мне) было бы удобнее понимать к какой статье комментарий относится. Впрочем, не настаиваю.
Евгений Степанищев (bolknote.ru) автор № 7
Комментарий для zencd.livejournal.com:

Я вот долго думал — что туда писать, пожалуй, можно и название статьи, да. Спасибо за идею!
razetdinov (razetdinov.ya.ru) № 8
Комментарий для zencd.livejournal.com:

http://razetdinov.ya.ru/replies.xml?item_no=104
Искал, ничего толкого не нашёл. В итоге создал ящик на гмыле и подписался по imap.
zencd.livejournal.com № 9
OMG! Gmail умеет отдавать RSS? Это гениально. Добавил запароленный feed в Google Reader, помотрим что получится. (А получается пока что простейший pipe!)
razetdinov (razetdinov.ya.ru) № 10
Комментарий для zencd.livejournal.com:

Уже пробовал, в гмэйловом RSS не отдаются тела сообщений :-(
zencd.livejournal.com № 11
Комментарий для razetdinov.ya.ru:

значит нужно просто найти другого емейл-провайдера
всё равно нам туда не заходить при новом раскладе :)
razetdinov (razetdinov.ya.ru) № 12
Комментарий для zencd.livejournal.com:

Я использую gmail-аккаунт исключительно для рассылок, читаю через imap, благо, Опера позволяет читать почту в одной ленте с рассылками. Но даже imap у гугла работает криво: http://razetdinov.ya.ru/replies.xml?item_no=178 Поэтому, если найдёшь лучше, свисти)
rin-nas.moikrug.ru № 13
Кол-во повторений в фигурных скобках {} в рег. выражениях имеет ограничение (65535 ?). Попробуйте отрезать 100000 символов :)

Мою реализацию utf8_substr() смотрите здесь:
http://forum.dklab.ru/viewtopic.php?t=17146

P.S.
Ввод несуществующего имени для OpenID получает PHP wanring и notice на странице.
rin-nas.moikrug.ru № 14
К сожалению, циклы в PHP тормозные в отличие, например, от C# и Python.
Где-то в интернете приводились тесты по этой теме.
Евгений Степанищев (bolknote.ru) автор № 15
Комментарий для rin-nas.moikrug.ru:

У меня задачи собственные, мне столько резать не надо :)

Warning: preg_replace(): Compilation failed: number too big in {} quantifier at offset 9 in /root/- on line 6

Но буду иметь ввиду, спасибо, я об этом не знал. Значит вариант такой — проверяем длину, далее — в зависимости от.