我需要将年龄分成其年龄表示为的组件,例如。 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;
?>
答案 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替代
$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',
)
---