在PHP中编译正则表达式

59

PHP中是否有一种方法可以编译正则表达式,以便可以将其与多个字符串进行比较而不重复编译过程?其他主要语言可以做到这一点--Java、C#、Python、Javascript等。

5个回答

46
Perl-Compatible Regular Expressions(PCRE)库可能已经针对您的使用情况进行了优化,而不像其他语言一样提供 Regex 类。该扩展程序维护了一个全局的每个线程缓存编译的正则表达式(最多4096个)。这就是PCRE Introduction所描述的。这就是Imran描述的study修饰符在调用之间存储编译表达式的方式。

我可以增加每个线程缓存的大小吗?4096的含义是什么? - sagar junnarkar
我认为它意味着4096个编译正则表达式。 - Tobia

18

preg正则表达式可以使用大写字母S(study)修饰符,这可能是您要查找的内容。

http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php

S

当一个模式将被多次使用时,值得花费更多时间进行分析,以加速匹配所需的时间。 如果设置了该修饰符,则执行此额外分析。 目前,研究模式仅对没有单个固定起始字符的非锚定模式有用。


10
回答OP的问题是,PHP中不需要预编译正则表达式,因为正如1stvamp指出的那样,编译过的正则表达式会自动缓存。 'S'修饰符是一个单独的问题。 - Alan Moore
此答案已添加到Stack Overflow正则表达式FAQ,位于“修饰符”下。 - aliteralmind

12

Thread是指当前脚本正在运行的线程。在第一次使用后,编译好的正则表达式会被缓存,下次再使用时PHP不会再次编译它。

简单测试:

<?php

function microtime_float() {
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
}

// test string
$text='The big brown <b>fox</b> jumped over a lazy <b>cat</b>';
$testTimes=10;


$avg=0;
for ($x=0; $x<$testTimes; $x++)
{
    $start=microtime_float();
    for ($i=0; $i<10000; $i++) {
        preg_match_all('/<b>(.*)<\/b>0?/', $text, $m);
    }
    $end=microtime_float();
    $avg += (float)$end-$start;
}

echo 'Regexp with caching avg '.($avg/$testTimes);

// regexp without caching
$avg=0;
for ($x=0; $x<$testTimes; $x++)
{
    $start=microtime_float();
    for ($i=0; $i<10000; $i++) {
        $pattern='/<b>(.*)<\/b>'.$i.'?/';
        preg_match_all($pattern, $text, $m);
    }
    $end=microtime_float();
    $avg += (float)$end-$start;
}

echo '<br/>Regexp without caching avg '.($avg/$testTimes);

使用缓存的正则表达式平均速度为0.1秒,不使用缓存的正则表达式平均速度为0.8秒。

使用缓存可以使正则表达式的速度快8倍!


2
“Test is NUL”!因为:在第二个例子中(没有缓存),您正在连接3个字符串,而在第一个例子中,“变量”$i不存在于模式中,并且它始终是该位置的0 - CSᵠ
2
测试仍然是相当有效的。通过在第一个测试中连接字符串"$j-$y"(其中$j=37$,$y=5$),并在第二个测试中连接字符串"$i-$x$"(-$x$是为了击败testTimes的任何缓存),我得到了0.0112和0.0431的时间。第二个测试中使用"$i-$y"也得到了同样的0.0431,这意味着缓存大小确实小于10000。因此,我的实际加速比是4倍(而不是8倍)。 - LSerni

7
正如另一个评论者已经说过的那样,PCRE正则表达式已经被编译,无需特别引用。PCRE通过内部哈希表以您提供的原始字符串为索引进行管理。

4
我不确定是否可以。如果您查看《精通正则表达式》,第10章讨论了一些PHP特定的优化技术。具体来说,使用S模式修饰符使正则表达式引擎在应用正则表达式之前“学习”它。根据您的模式和文本,这可能会带来一些速度上的改进。
编辑:您可以通过books.google.com预览该书的内容。

每个使用正则表达式的开发者都应该阅读这本书!!你需要提高效率的所有技巧都在这本书中。 - Arno

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接