性能明智的字符串匹配

时间:2010-01-06 03:58:43

标签: php regex string string-matching strpos

我有一个通用的数据库查询函数,每次发出SQL查询时都会运行以下检查:

  1. if (preg_match('~^(?:UPDATE|DELETE)~i', $query) === 1)
  2. if (preg_match('~^(?:UPDATE|DELETE)~iS', $query) === 1)
  3. if ((stripos($query, 'UPDATE') === 0) || (stripos($query, 'DELETE') === 0))
  4. 我知道简单的strpos()来电比做preg_match()要快,但是因为我打电话给 strIpos()两次我真的不是确定哪一个应该表现得更好。

    第二个选项中的S模式修饰符也会在手册中引起一些困惑:

      

    何时使用图案   好几次,值得花钱   更多的时间来分析它   加快匹配所需的时间。   如果设置了此修改器,那么这个   进行额外的分析。在   目前,研究模式是有用的   仅适用于非锚定模式   没有一个固定的起点   字符。

    在这种情况下,速度并不重要(否则我不会使用这种通用查询功能)但是,我仍然希望尽可能快地运行它,同时保持它的简单性。

    我应该选择以上哪个选项?


    编辑:run a simple benchmark仍然无法确定哪种方法效果更好。

    以下是 10,000次尝试的结果(总时间,以秒为单位):

    Array
    (
        [match] => Array
            (
                [stripos] => 0.0965
                [preg_match] => 0.2445
                [preg_match?] => 0.1227
                [preg_match?S] => 0.0863
            )
    
        [no-match] => Array
            (
                [stripos] => 0.1165
                [preg_match] => 0.0812
                [preg_match?] => 0.0809
                [preg_match?S] => 0.0829
            )
    )
    

    100,000次尝试

    Array
    (
        [match] => Array
            (
                [stripos] => 1.2049
                [preg_match] => 1.5079
                [preg_match?] => 1.5564
                [preg_match?S] => 1.5857
            )
    
        [no-match] => Array
            (
                [stripos] => 1.4833
                [preg_match] => 0.8853
                [preg_match?] => 0.8645
                [preg_match?S] => 0.8986
            )
    )
    

    1,000,000次尝试

    Array
    (
        [match] => Array
            (
                [stripos] => 9.4555
                [preg_match] => 8.7634
                [preg_match?] => 9.0834
                [preg_match?S] => 9.1629
            )
    
        [no-match] => Array
            (
                [stripos] => 13.4344
                [preg_match] => 9.6041
                [preg_match?] => 10.5849
                [preg_match?S] => 8.8814
            )
    )
    

    10,000,000次尝试

    Array
    (
        [match] => Array
            (
                [stripos] => 86.3218
                [preg_match] => 93.6755
                [preg_match?] => 92.0910
                [preg_match?S] => 105.4128
            )
    
        [no-match] => Array
            (
                [stripos] => 150.9792
                [preg_match] => 111.2088
                [preg_match?] => 100.7903
                [preg_match?S] => 88.1984
            )
    )
    

    正如您所看到的结果差异很大,这让我想知道这是否是进行基准测试的正确方法。

2 个答案:

答案 0 :(得分:2)

我可能不会使用任何这些。我不能确定没有基准测试,但我认为substr()stripos更快,因为它不会扫描整个字符串。假设UPDATEDELETE总是出现在查询的开头,甚至更好,它们都只有6个字符长,所以你可以在一个substr()中完成:

$queryPrefix = strtoupper(substr($query,0,6));
if ($queryPrefix == 'UPDATE' || $queryPrefix == 'DELETE') {

如果需要,可以在那里为任何前缀空格添加trim(),但可能没有必要。

如果你正在使用UPDATE和DELETE进行嵌套或子查询,那么显然上面的方法不起作用,我会选择stripos()路由。如果你可以避免使用正则表达式来支持普通的字符串函数,那么它会更快,更简单。

答案 1 :(得分:0)

我使用了以下正则表达式,因为它们似乎更快(在匹配和不匹配的文本上):

  1. if (preg_match('~^(?:INSERT|REPLACE)~i', $query) === 1)
  2. else if (preg_match('~^(?:UPDATE|DELETE)~i', $query) === 1)
  3. else if (preg_match('~^(?:SELECT|EXPLAIN)~i', $query) === 1)