【问题标题】:php's preg_replace() versus(vs.) ord()php preg_replace() 与(vs.) ord()
【发布时间】:2010-10-22 09:04:20
【问题描述】:

camelCase 下划线更快; 使用 preg_replace() 还是使用 ord() ?

我的猜测是使用 ord 的方法会更快, 因为 preg_replace 可以做的比需要的多。

<?php
function __autoload($class_name){
    $name = strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $class_name));
    require_once("some_dir/".$name.".php");
}
?>

<?php
function __autoload($class_name){
// lowercase first letter
$class_name[0] = strtolower($class_name[0]);

$len = strlen($class_name);
for ($i = 0; $i < $len; ++$i) {
    // see if we have an uppercase character and replace
    if (ord($class_name[$i]) > ord('A') && ord($class_name[$i]) < ord('Z')) {
        $class_name[$i] = '_' . strtolower($class_name[$i]);
        // increase length of class and position
        ++$len;
        ++$i;
    }
}

return $class_name;
}
?>

免责声明——取自StackOverflowQuestion 1589468的代码示例。

编辑,在jensgram 的数组建议并找到array_splice 之后,我想出了以下内容:

<?php
function __autoload ($string)// actually, function camel2underscore
{
$string  =  str_split($string);
$pos     =  count( $string );
while ( --$pos > 0 )
{
    $lower  =  strtolower( $string[ $pos ] );
    if ( $string[ $pos ] === $lower )
    {
        // assuming most letters will be underscore this should be improvement
        continue;
    }
    unset( $string[ $pos ] );
    array_splice( $string , $pos , 0 , array( '_' , $lower ) );
}
$string  =  implode( '' , $string );
return $string;
}
// $pos could be avoided by using the array key, something i might look into later on.
?>

当我将测试这些方法时,我将添加这个 但请随时告诉我您的结果;p

【问题讨论】:

  • 判断什么是更快的最好方法是尝试一下。你有吗?
  • 获取您最喜欢的分析器和基准
  • 可能对阅读以下内容的人来说很有趣:paulferrett.com/2009/php-camel-case-functionswebdevblog.info/php/…
  • bwah,我会把它放在我的待办事项清单上,这只是一个可以由已经做过这个和/或熟悉分析/基准测试的人来回答的问题。

标签: php function comparison performance


【解决方案1】:

我认为(而且我非常确定)preg_replace 方法会更快 - 但如果您想知道,为什么不做一个小基准测试调用这两个函数 100000 次并测量时间?

【讨论】:

    【解决方案2】:

    (不是一个答案,但太长了不能成为评论 - 将 CW)

    如果你要比较的话,你至少应该在ord()版本上做一些优化。

    $len = strlen($class_name);
    $ordCurr = null;
    $ordA = ord('A');
    $ordZ = ord('Z');
    for ($i = 0; $i < $len; ++$i) {
        $ordCurr = ord($class_name[$i]);
        // see if we have an uppercase character and replace
        if ($ordCurr >= $ordA && $ordCurr <= $ordZ) {
            $class_name[$i] = '_' . strtolower($class_name[$i]);
            // increase length of class and position
            ++$len;
            ++$i;
        }
    }
    

    此外,将名称压入堆栈(数组)并在末尾加入可能比字符串连接更有效。

    但是首先值得优化/分析吗?

    【讨论】:

    • 还有更多用处,$class_name[$i] = '_' . strtolower($class_name[$i]); 不能按预期工作...
    • @immeëmosol 不,至少您应该为结果保留一个新字符串。我并没有真正深入研究代码 - 只是想说明一些简单的技术:)
    • 你的数组想法让我开始着手不同的实现。在某个时候,我将测试它们的速度(顺便说一下,我不喜欢没有换行符的 cmets :s )。因此,我会将代码放在评论中。
    【解决方案3】:

    我的用例与 OP 略有不同,但我认为它仍然说明了 preg_replace 和手动字符串操作之间的区别。

    $a = "16 East, 95 Street";
    
    echo "preg: ".test_preg_replace($a)."\n";
    echo "ord:  ".test_ord($a)."\n";
    
    $t = microtime(true);
    for ($i = 0; $i &lt 100000; $i++) test_preg_replace($a);
    echo (microtime(true) - $t)."\n";
    $t = microtime(true);
    for ($i = 0; $i &lt 100000; $i++) test_ord($a);
    echo (microtime(true) - $t)."\n";
    
    function test_preg_replace($s) {
        return preg_replace('/[^a-z0-9_-]/', '-', strtolower($s));
    }
    function test_ord($s) {
        $a = ord('a');
        $z = ord('z');
        $aa = ord('A');
        $zz = ord('Z');
        $zero = ord('0');
        $nine = ord('9');
        $us = ord('_');
        $ds = ord('-');
        $toret = ''; 
        for ($i = 0, $len = strlen($s); $i < $len; $i++) {
            $c = ord($s[$i]);
            if (($c >= $a && $c &lt;= $z) 
                || ($c >= $zero && $c &lt;= $nine)
                || $c == $us 
                || $c == $ds)
            {   
                $toret .= $s[$i];
            }   
            elseif ($c >= $aa && $c &lt;= $zz)
            {   
                $toret .= chr($c + $a - $aa); // strtolower
            }   
            else
            {   
                $toret .= '-';
            }   
        }   
        return $toret;
    }
    

    结果是

    0.42064881324768
    2.4904868602753
    

    所以 preg_replace 方法非常优越。此外,字符串连接比插入数组并内爆稍快。

    【讨论】:

      【解决方案4】:

      如果您只想将驼峰式大小写转换为下划线,那么您可能可以编写一个比 ord 或 preg_replace 更有效的函数来执行此操作,而且花费的时间比分析它们所需的时间要短。

      【讨论】:

      • 我希望使用最后添加的方法,但仍然会在某个非常可怕的晴天描述它们。
      【解决方案5】:

      我使用以下四个函数编写了一个基准测试,我发现在 Magento 中实现的那个是最快的(它是 Test4):

      测试1:

      /**
       * @see: http://www.paulferrett.com/2009/php-camel-case-functions/
       */
      function fromCamelCase_1($str)
      {
          $str[0] = strtolower($str[0]);
          return preg_replace('/([A-Z])/e', "'_' . strtolower('\\1')", $str);
      }
      

      测试2:

      /**
       * @see: http://stackoverflow.com/questions/3995338/phps-preg-replace-versusvs-ord#answer-3995435
       */
      function fromCamelCase_2($str)
      {
          // lowercase first letter
          $str[0] = strtolower($str[0]);
      
          $newFieldName = '';
          $len = strlen($str);
          for ($i = 0; $i < $len; ++$i) {
              $ord = ord($str[$i]);
              // see if we have an uppercase character and replace
              if ($ord > 64 && $ord < 91) {
                  $newFieldName .= '_';
              }
              $newFieldName .= strtolower($str[$i]);
          }
          return $newFieldName;
      }
      

      测试3:

      /**
       * @see: http://www.paulferrett.com/2009/php-camel-case-functions/#div-comment-133
       */
      function fromCamelCase_3($str) {
          $str[0] = strtolower($str[0]);
          $func = create_function('$c', 'return "_" . strtolower($c[1]);');
          return preg_replace_callback('/([A-Z])/', $func, $str);
      }
      

      测试4:

      /**
       * @see: http://svn.magentocommerce.com/source/branches/1.6-trunk/lib/Varien/Object.php :: function _underscore($name)
       */
      function fromCamelCase_4($name) {
          return strtolower(preg_replace('/(.)([A-Z])/', "$1_$2", $name));
      }
      

      使用字符串“getExternalPrefix” 1000 次的结果:

      fromCamelCase_1: 0.48158717155457
      fromCamelCase_2: 2.3211658000946
      fromCamelCase_3: 0.63665509223938
      fromCamelCase_4: 0.18188905715942
      

      使用诸如“WAytGLPqZltMfHBQXClrjpTYWaEEkyyu”之类的随机字符串 1000 次的结果:

      fromCamelCase_1: 2.3300149440765
      fromCamelCase_2: 4.0111720561981
      fromCamelCase_3: 2.2800230979919
      fromCamelCase_4: 0.18472790718079
      

      使用测试字符串我得到了不同的输出——但这不应该出现在你的系统中:

      original:
      MmrcgUmNfCCTOMwwgaPuGegEGHPzvUim
      
      last test:
      mmrcg_um_nf_cc_to_mwwga_pu_geg_eg_hpzv_uim
      
      other tests:
      mmrcg_um_nf_c_c_t_o_mwwga_pu_geg_e_g_h_pzv_uim
      

      正如您在时间戳中看到的那样 - 最后一个测试在两个测试中具有相同的时间 :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-14
        • 2013-08-03
        相关资源
        最近更新 更多