将逗号分隔列表转换为数组 - explode vs preg_split

时间:2016-09-09 04:08:49

标签: php arrays

我用逗号分隔城市名称列表。 ($ cityNames可能包含100到500个名称)

$cityNames = "Chicago, San Diego, El Paso";

以下哪一项最好将逗号分隔列表转换为数组,同时还要考虑性能和准确性?

$cityNamesArray = explode(",", $cityNames);

$cityNamesArray = preg_split('/\s*,\s*/', $cityNames, -1, PREG_SPLIT_NO_EMPTY);

注意: - 逗号分隔列表由用户使用textarea提供。

3 个答案:

答案 0 :(得分:2)

我总是试图指出解决方案的正确性始终优先于它的工作速度。一些不起作用但速度非常快的东西就像一个有效的东西一样,但是真的很慢。

因此,我将分别解决解决方案的正确性和效率。

正确性

explode()trim()array_map()的组合,可以很好地实现您期望的目标。

$cityNamesArray = array_map('trim', explode(',', $cityNames ));

您也可以在此处输入array_filter()以确保零长度字符串不会通过。所以在像"Chicago, San Diego, El Paso,, New York,"这样的字符串中,你不会得到一个带有一些空值的数组。

$cityNamesArray = array_filter(array_map('trim', explode(',', $cityNames )), 'strlen');

这假设数据可能不一致,并且中断对所需的最终结果产生不利影响。所以解决方案的正确性与此有关。

此处函数调用的组合会导致数组多次迭代,因此您有O(n * 2 + k)时间,其中k是字符串中要查找定界的数字字符,而n是生成的数组中的元素数量通过array_maparray_filter

速度

现在考虑如何让它更快,我们需要让大O更接近O(k)以获得最佳解决方案,因为你无法通过单个字符进一步减少k needle / haystack substring search。

preg_split('/\s*,\s*/', $cityNames, -1, PREG_SPLIT_NO_EMPTY)方法的时间复杂度约为O(k),因为如果PCRE VM中有多次传递,则不大于O(k + 1)或最差情况O(k + log k)

它也适用于$cityNames = "Chicago, San Diego, El Paso,, New York,"或类似结果的上述情况。

这意味着它符合正确性和效率的标准。因此,我认为这是最佳解决方案。

替补标记

话虽如此,我认为你会发现两种方法之间的性能差异可以忽略不计。

这是一个基本的基准,以证明差异对平均投入的影响微不足道。

$cityNames = "Chicago, San Diego,El Paso,,New York,  ,"; // sample data

$T = 0; // total time spent

for($n = 0; $n < 10000; $n++) {
    $t = microtime(true); // start time
    preg_split('/\s*,\s*/', $cityNames, -1, PREG_SPLIT_NO_EMPTY);
    $t = microtime(true) - $t; // end time
    $T += $t; // aggregate time
}

printf("preg_split took %.06f seconds on average", $T / $n);


$T = 0; // total time spent

for($n = 0; $n < 10000; $n++) {
    $t = microtime(true); // start time
    array_filter(array_map('trim', explode(',', $cityNames )), 'strlen');
    $t = microtime(true) - $t; // end time
    $T += $t; // aggregate time
}

printf("array functions took %.06f seconds on average", $T / $n);
preg_split took 0.000003 seconds on average
array functions took 0.000005 seconds on average

这是它们之间的平均差异,可能是1或2微秒。当测量这种微小的速度差异时,只要解决方案产生正确性,你就不应该太在意。解决性能问题的更好方法是按数量级进行测量。一个快1或2微秒的解决方案不值得探索,如果它花费更多的时间,而不仅仅是使用几乎的现有解决方案,但同样正确。但是,可能会快速提高1或2个数量级的解决方案。

答案 1 :(得分:1)

According to PHP.NET

  

提示如果您不需要正则表达式的强大功能,您可以选择   更快(尽管更简单)的替代方案,如explode()或str_split()。

关于准确性,在这两种情况下都会出现问题,如在给定的示例中,您将拥有以下数组:

[1] => "Chicago"
[2] => " San Diego"
[3] => " El Paso"

(注意[2]和[3]中的额外空间)

解决这个问题的一种方法是替换所有出现的&#34;,&#34;到&#34;,&#34;像这样:

$cityNames = str_replace(', ', ',', $cityNames);

编辑:(失眠让我变得更好)

请确保在分隔符中包含空格:

$cityNamesArray = explode(", ", $cityNames);

答案 2 :(得分:0)

在一个简单的用法中,explode()要快一些,请参阅:http://micro-optimization.com/explode-vs-preg_split

但是preg_split的优点是支持标签(\ t)和空格用\ s。

\ s元字符用于查找空白字符。

空格字符可以是(http://php.net/manual/en/regexp.reference.escape.php):

  • 空格字符(32 = 0x20)

  • 制表符(9 = 0x09)

  • 回车符(13 = 0x0D)

  • 新行字符(10 = 0x0A)

  • 换页符(12 = 0x0C)

在这种情况下,您应该看到成本和收益。

提示,使用array_filter“删除”数组中的空项:

示例:

$ keyword = explore('',$ _GET ['search']); //或preg_split 的print_r($关键字);

$ keyword = array_filter($ arr,'empty'); 的print_r($关键字);

注意:RegExp Perfomance