解释我的问题的最好方法就是向你展示。
输入字符串:
/04-11-2010/12:45/
获取日期和时间部分的正则表达式:
preg_match('@/(\d\d)-(\d\d)-(\d\d\d\d)/(\d\d):(\d\d)/@', $input, $matches);
PHP 匹配数组:
Array
(
[0] => /01-11-2010/12:45/
[1] => 01
[2] => 11
[3] => 2010
[4] => 12
[5] => 45
)
现在,上面的正则表达式可以完美地获取表示输入字符串中的日期和时间的各个组成部分。
问题是时间部分需要是可选的,而不需要删除整个正则表达式。
问题输入字符串:
/04-11-2010//
PHP 匹配数组
Array
(
)
基本上我需要由匹配数组返回的是:
Array
(
[0] => /01-11-2010/12:45/
[1] => 01
[2] => 11
[3] => 2010
[4] =>
[5] =>
)
注意数组元素 4 和 5 仍然需要存在,但返回空。
使用问号运算符和非捕获组使内容成为可选。
@/(\d\d)-(\d\d)-(\d\d\d\d)/(?:(\d\d):(\d\d))?/@
我不确定它如何与匹配数组交互 - 如果空数组元素绝对重要,您可能需要改为
@/(\d\d)-(\d\d)-(\d\d\d\d)/((?:\d\d)?):?((?:\d\d)?)/@
它有自己的误报(当时的冒号现在是可选的)。
将第二部分设为可选:
'@/(\d\d)-(\d\d)-(\d\d\d\d)/(?:(\d\d):(\d\d))?/@'
这里使用了非捕获组
(?:…)
,无法引用,因此不会更改匹配组。
@/(\d\d)-(\d\d)-(\d\d\d\d)/((?:\d\d)?):?((?:\d\d)?)/@
做你想做的事(即填充第4组和第5组),但也接受不完整的时间,如
/04-11-2010/12:/
不知道你是否适合
我不是 php 专家,但是怎么样:
preg_match('@/(\d\d)-(\d\d)-(\d\d\d\d)/(\d\d)?:?(\d\d)?/@', $input, $matches);
就正则表达式而言,它应该匹配没有时间字段的字符串。
@OP,不需要混乱的正则表达式。
$str="/04-11-2010/12:45/";
$s = array_filter(explode('/',$str));
$date=$s[1];
$time=$s[2];
$date_parts=explode("-",$date);
$time_parts=explode(":",$time);
if ( checkdate($date_parts[1],$date_parts[0],$date_parts[2]) ){
print "date ok\n";
}
使用本机 PHP 函数来完成此任务,使用正则表达式有点过分了。
PHP 5 有 date_parse 函数:
$string = '/04-11-2010/12:45/';
$dateArray = date_parse(str_replace('/', ' ', $string));
print_r($dateArray);
$string = '/04-11-2010//';
$dateArray = date_parse(str_replace('/', ' ', $string));
print_r($dateArray);
输出:
Array
(
[year] => 2010
[month] => 11
[day] => 4
[hour] => 12
[minute] => 45
[second] => 0
[fraction] => 0
[warning_count] => 0
[warnings] => Array
(
)
[error_count] => 0
[errors] => Array
(
)
[is_localtime] =>
)
Array
(
[year] => 2010
[month] => 11
[day] => 4
[hour] =>
[minute] =>
[second] =>
[fraction] =>
[warning_count] => 0
[warnings] => Array
(
)
[error_count] => 0
[errors] => Array
(
)
[is_localtime] =>
)
PHP 5.3 有一个更灵活的 date_parse_from_format 函数,您也可以使用。
我将演示一些从时间可选的 DateTime 表达式中解析或提取数据的工作技术。 请参阅此 demo 以获取其输出的证明。
解析日期/日期时间表达式的首要考虑因素应该是合法的日期时间解析器。 仅当您有令人信服的理由时才偏离此选择。
在这种情况下,在确定动态表达式是否具有时间成分后解析动态表达式。无论哪种方式,请在格式参数的末尾添加一个管道,以将任何缺失的日期时间值清零。 这将创建一个对象而不是数组,但根据您的下一步,这可能是从中提取值的理想来源
var_export(
DateTime::createFromFormat(
str_contains($test, ':')
? '/d-m-Y/H:i/|'
: '/d-m-Y//|',
$test
)
);
对于填充所需数组的最直接方法,
sscanf()
是可行的,因为可选组件位于字符串的末尾。如果未遇到尾随时间值,则将作为 null
元素返回。
var_export(
sscanf(
$test,
'/%02s-%02s-%04s/%02[^/:]:%02[^/:]'
)
);
输入到
preg_split()
的一个或多个非数字字符的正则表达式在人眼看来非常容易,并返回一个平面数组,但当输入中未提供时间元素时,需要用 null
时间元素填充字符串。
var_export(
array_pad(
preg_split(
'/\D+/',
$test,
0,
PREG_SPLIT_NO_EMPTY
)
5,
null
),
);
preg_match()
可能是一个舒适的调用,如果需要验证,它比 preg_split()
更有优势,但它的输出是一个引用变量,其中包含必须关闭的完整字符串匹配。将时间表达式设为可选,并设置 PREG_UNMATCHED_AS_NULL
标志以在缺少时间值时获得 null
元素。
var_export(
preg_match(
'#/(\d{2})-(\d{2})-(\d{4})/(?:(\d{2}):(\d{2})/)?#',
$test,
$matches,
PREG_UNMATCHED_AS_NULL
)
? array_slice($matches, 1)
: []
);
最后,最没有吸引力的选项是对字符串进行标记。 不仅在此 IIFE 内部使用循环来进行迭代
strtok()
调用,返回的数组仍然需要附加 null
时间元素。 这简直就是丑陋。
var_export(
(function($tokens) {
while ($t = strtok('/:-')) {
$tokens[] = $t;
}
return $tokens + [3 => null, 4 => null];
})([strtok($test, '/:-')])
);