我想做什么
在 php 中,像这样:
$input = '23:10';
$pattern = '/^('d?'d):('d?'d)(:('d?'d))?$/';
$rewrite = '$1h$2m$4s';
$output = preg_replace( $pattern, $rewrite, $input );
echo $output;
$input
可以是有或没有秒的时间,但没有秒,它应该返回"0"作为替换字符串中$4
的默认值。所以输出,现在是:
23h10ms
应该是:
23h10m0s
重要:
对于解决方案,最终函数的输入由任意$pattern
和$rewrite
字符串组成非常重要,这些字符串将$input
字符串转换为输出格式。因此,没有对该秒部分进行硬编码检查,而是实际上是在$rewrite
字符串中插入引用默认值的通用方法,这些引用引用$pattern
字符串中的可选部分。该函数还应该适用于以下情况(例如):
$input = '3 hours';
$pattern = '/^('d+) hours( and ('d+) minutes)?( and ('d+) seconds)?$/';
$rewrite = '$1h$3m$5s';
如本例所示,我无法控制所需的格式($pattern
+ $rewrite
),因此它们可能会有很大差异。最重要的原因是:输入和输出也可以/将使用其他语言,因此$pattern
和$rewrite
是从语言文件(Joomla)中获得的。
解决方案的可能方向
到目前为止,我最接近的是以下内容:
// Get a $matches array:
preg_match( $pattern, $input, $matches );
// Replace the references ($1, $2, etc.) in the rewrite string by these matches:
$output = preg_replace_callback(
'/'$('d+)/g',
function( $m ) {
$i = $m[1];
return ( isset( $matches[$i] ) ? $matches[$i] : '0' );
},
$rewrite
);
关于这一点的两件事:1.它还不起作用,因为$matches在回调函数中不可用。2. 使用重写字符串作为 preg_replace_callback() 的输入变得非常棘手。
更新
为了使想要的功能是动态的,我建议编写一个新类,其中所有需要的信息都是属性。在该类中,您可以使用成员方法调用preg_replace_callback
,并检查是否存在所有需要的组 - 如果不存在,则应将其替换为定义的$defaultValue
。
class ReplaceWithDefault {
private $pattern, $replacement, $subject, $defaultValue;
public function __construct($pattern, $replacement, $subject, $defaultValue) {
$this->pattern = $pattern;
$this->replacement = $replacement;
$this->subject = $subject;
$this->defaultValue = $defaultValue;
}
public function replace() {
return preg_replace_callback($this->pattern, 'self::callbackReplace', $this->subject);
//alternative: return preg_replace_callback($this->pattern, array($this, 'callbackReplace'), $this->subject);
}
private function callbackReplace($match) {
// fill not found groups with defaultValue
if (preg_match_all('/'$'d{1,}/i', $this->replacement, $values)) {
foreach ($values[0] as $value) {
$index = substr($value, 1);//get rid of $ sign
if (!array_key_exists($index, $match)) {
$match[$index] = $this->defaultValue;
}
}
}
$result = $this->replacement;
// do the actual replacement
krsort($match);
foreach ($match as $key=>$value) {
$result = str_replace('$'.$key, $value, $result);
}
return $result;
}
}
你需要krsort()
,所以它不会出错,例如 $15
{$1}5
.
该类现在可以像这样使用
$originalQuestion = new ReplaceWithDefault('/^('d?'d):('d?'d)(:('d?'d))?$/',
'$1h$2m$4s',
'23:10',
'00');
$updatedQuestion = new ReplaceWithDefault('/^('d+) hours( and ('d+) minutes)?( and ('d+) seconds)?$/',
'$1h$3m$5s',
'3 hours',
'0');
print "<pre>";
var_dump($originalQuestion->replace());
var_dump($updatedQuestion->replace());
并将产生想要的结果。
原始帖子
我不确定这是否可以用常规preg_replace()
来完成.但是,PHP提供了另一种可能性:preg_replace_callback()
。定义函数时,可以使用更复杂的逻辑。
$input = '23:10';
$pattern = '/^('d?'d):('d?'d)(:('d?'d))?$/';
function correctFormat($hit) {
if (isSet($hit[4]))
$seconds = $hit[4];
else
$seconds = "0";
return $hit[1]."h".$hit[2]."m".$seconds."s";
}
$output = preg_replace_callback( $pattern, "correctFormat" , $input );
echo $output;
我建议使用 Chinnu R 所示的解决方案,因为在这种情况下,正则表达式显然不是必需的,并且对常规爆炸没有任何优势。
希望对您有所帮助,
$input = '23:10';
list($h, $m,$s) = explode(":", date('H:i:s', strtotime($input)));
echo $h."h".$m."m".$s."s";
另一种方法;
$input = '23:10';
list($h, $m, $s) = explode(":", $input);
if($s==""){ $s="00";};
echo $h."h".$m."m".$s."s";