2 заметки с тегом

pcre

«Глаголы» в PCRE

В известной библиотеке «PCRE», реализующей Перл-подобные регулярные выражения, есть такая штука как «глаголы» (в оригинале — VERB). Это ключевые слова, указывающиеся в скобках и начинающиеся со звёздочки. Когда-то я рассказывал об одном из них — «глаголе» UCP, который позволяет полноценно использовать ЮТФ-8 в этой библиотеке.

Но есть и другие, на самом деле их довольно много, причём их применение очень разнообразно. Мне редко ими приходится пользоваться, вероятно по той причине, что я всё реже пользуюсь регулярными выражениями вообще. Впрочем, смотря с чем сравнивать.

Самые популярные «глаголы» в моём рационе (если исключить UCP), это — ACCEPT и FAIL. Сейчас на небольших примерах из документации расскажу что это.

«Глагол» ACCEPT даёт понять библиотеке, что дальше можно не искать — найденное нас устроило. Вот смотрите:

A((?:A|B(*ACCEPT)|C)D)

Если подставить в эту регулярку «ACD», то ничего необычного не произойдёт: совпадение выглядит ожидаемым способом:  A((?:A|B(*ACCEPT)|C)D), выглядит так, как будто строка для проверки всегда обязана заканчиваться на «D», по если передать сюда «AB», то совпадение тоже будет: A((?:A|B(*ACCEPT)|C)D) — «глагол» ACCEPT говорит о том, что дальше можно не продолжать, остаток нас не интересует.

«Глагол» FAIL позволяет достичь ровно противоположного и, в частности, сформировать отрицание, которое другими средствами добиться тяжелее и представляет сложность для новичков в регулярках.

A(?:BCD(*FAIL)|.*?)E

Если передать сюда строки «ABCE», «AEEE», «AwhateverE» совпадение произойдёт по следующим правилам шаблона: A(?:BCD(*FAIL)|.*?)E, но если передать «ABCDE», то совпадения не будет, вступит в силу «глагол» FAIL: A(?:BCD(*FAIL)|.*?)E.

Эти и другие «глаголы» (кроме MARK) отлично работают в ПХП, потому что фукнции «preg_*» как раз используют библиотеку PCRE у себя внутри.

PCRE и UTF-16

Прочитал в документации по библиотеке PCRE, что с версии 8.30 она поддерживает кодировку UTF-16. Решил сравнить производительность по сравнению с UTF-8. Всё-таки кодировка UTF-16 (почти) фиксированного размера, обрабатывать её сильно проще, чем UTF-8, которая переменной длины.

Написал два примера на Си: один для UTF-8, второй для UTF-16 и запустил, разницу посмотрите сами:

# это я на своём «Маке» скомпилировал
~$ gcc-4.7 -I/usr/local/Cellar/pcre/8.32/include/ -L/usr/local/Cellar/pcre/8.32/lib/ -lpcre -std=c99 -o utf8 utf8.c
~$ gcc-4.7 -I/usr/local/Cellar/pcre/8.32/include/ -L/usr/local/Cellar/pcre/8.32/lib/ -lpcre16 -std=c99 -o utf16 utf16.c

# два файла в разных кодировках, почти 1,5 млн. строк, правда используется далеко не это количество
~$ wc -l utf8.txt
 1424462 utf8.txt
~$ wc -l utf16.txt
 1424462 utf16.txt

~$ time ./utf8
PCRE version: 8.32 2012-11-30
Yes!
…
Yes!

real	0m1.372s
user	0m1.286s
sys	0m0.039s

~$ time ./utf16
PCRE version: 8.32 2012-11-30
Yes!
…
Yes!

real	0m0.048s
user	0m0.004s
sys	0m0.035s

Либо я где-то неверно что-то напрограммировал, либо разница почти в 29 раз!

Лично мне кажется, что API толком не работает и ошибка в том, что в pcre16_compile не указывается длина шаблона.