在PHP中拆分多个字符的字符串

时间:2014-03-15 06:59:13

标签: php explode

我需要将年龄分成其年龄表示为的组件,例如。 27y5m6w2d或这些值的任意组合。例如。 2w3d或27d或5y2d等。结果必须最多包含4个变量$ yrs,$ mths,$ wks和包含相应数值的$ days。

我可以用这段代码来做,但我希望有更高效的东西:

$pos = strpos($age, 'y');
if ($pos !== false)
   list($yrs, $age) = explode('y', $age);
$pos = strpos($age, 'm');
if ($pos !== false)
   list($mths, $age) = explode('m', $age);
$pos = strpos($age, 'w');
if ($pos !== false)
   list($wks, $age) = explode('w', $age);
$pos = strpos($age, 'd');
if ($pos !== false)
   list($days, $age) = explode('d', $age);

如果您有建议,请在10,000次迭代循环中运行并告知结果。对于10,000次迭代,上面的代码平均运行0.06秒。我用这段代码来测试:

<?php
$startTime = microtime(true);

// code goes here

echo "Time:  " . number_format(( microtime(true) - $startTime), 4) . " Seconds<br>"; 
echo 'y='.$yrs.' m='.$mths.' w='.$wks.' d='.$days;
?>

3 个答案:

答案 0 :(得分:1)

我建议使用与preg_match_all()匹配的正则表达式,如下所示:

$input = '2w3d'
$matches = array();
preg_match_all('|(\d+)([ymwd])|', $input, $matches, PREG_SET_ORDER);

输出数组$matches将保存此模式中的所有匹配项:

$matches = array(
    // 0 => matched string, 1 => first capture group, 2 => second capture group 
    0 => array( 0 => '2w', 1 => '2', 2 => 'w' ),
    1 => array( 0 => '3d', 1 => '3', 2 => 'd' )
);

编辑:
像这样处理这个结果:

$yrs = $mths = $wks = $days = 0;
foreach($matches as $match) {
    switch($match[2]) {
        case 'y': $yrs = (int)$match[1]; break;
        case 'm': $mths = (int)$match[1]; break;
        case 'w': $wkss = (int)$match[1]; break;
        case 'd': $days = (int)$match[1]; break;
    }
}

<小时/> 编辑2:Hacky替代
使用字符比较,在100.000次迭代中大约需要0.4秒。

$number = '';
for($j = 0, $length = strlen($input); $j < $length; $j++) {
    if($input[$j] < 'A') {
        $number .= $input[$j];
    } else {
        switch($input[$j]) {
            case 'y': $yrs = (int)$number; break;
            case 'm': $mths = (int)$number; break;
            case 'w': $wks = (int)$number; break;
            case 'd': $days = (int)$number; break;
        }
        $number = '';
    }
}

答案 1 :(得分:0)

我会采用以下方法。

$age = '27y5m6w2d';

// Split the string into array of numbers and words
$arr = preg_split('/(?<=[ymdw])/', $age, -1, PREG_SPLIT_NO_EMPTY);

foreach ($arr as $str) 
{
    $item = substr($str, -1); // Get last character
    $value = intval($str);    // Get the integer

    switch ($item) 
    {
        case 'y':
            $year = $value;
            break;        
        case 'm':
            $month = $value;
            break;
        case 'd':
            $day = $value;
            break;
        case 'w':
            $week = $value;
            break;
    }
}

代码更易读,速度更快。我用10000次迭代测试了它,它花了大约0.0906秒。

答案 2 :(得分:0)

您不需要使用查找数组或切换块来膨胀代码。

您的输入字符串具有可预测的格式(顺序),因此您可以在输入字符串的每个预期“单元”处编写一个包含可选捕获组的正则表达式模式。虽然使用命名捕获组提供了一些声明上的好处,但同时也膨胀了正则表达式模式和输出数组-因此我通常不喜欢使用它们。

您会注意到正则表达式中有一个重复的格式:(?:(\d+)unitLetter)?。这使得修改/扩展模式非常简单。所有这些子模式都使目标子字符串成为“可选”,并且子模式中的最后一个字母区分了被隔离的时间单位。

在这种情况下,匹配输出结构为:

  • [0]:完整的字符串匹配项(我们不需要)
  • [1]:年
  • [2]:毫秒
  • [3]:wks
  • [4]:天

代码:(Demo

$strings = ['27y5m6w2d', '1m1w', '2w3d', '999y3w', '27d', '5y2d'];
foreach ($strings as $string) {
    preg_match('~(?:(\d+)y)?(?:(\d+)m)?(?:(\d+)w)?(?:(\d+)d)?~', $string, $m);
    var_export([
        'yrs' => $m[1] ?? '',
        'mths' => $m[2] ?? '',
        'wks' => $m[3] ?? '',
        'days' => $m[4] ?? '',
    ]);
    echo "\n---\n";
}

输出:

array (
  'yrs' => '27',
  'mths' => '5',
  'wks' => '6',
  'days' => '2',
)
---
array (
  'yrs' => '',
  'mths' => '1',
  'wks' => '1',
  'days' => '',
)
---
array (
  'yrs' => '',
  'mths' => '',
  'wks' => '2',
  'days' => '3',
)
---
array (
  'yrs' => '999',
  'mths' => '',
  'wks' => '3',
  'days' => '',
)
---
array (
  'yrs' => '',
  'mths' => '',
  'wks' => '',
  'days' => '27',
)
---
array (
  'yrs' => '5',
  'mths' => '',
  'wks' => '',
  'days' => '2',
)
---