提取时间戳和注释的正则表达式

4

我有一些从旧的access数据库导出的文本字段,正在转移到新的MySQL结构中。它们的格式为:

10/06/2010 09:10:40 工作尚未开始

我想使用某种正则表达式提取日期/时间信息和之后的注释。

是否有一个简单的正则表达式语法可以匹配这些信息?


为什么要使用正则表达式?看起来你有固定的字段长度和一个相当标准的日期格式。 - Annika Backstrom
10个回答

8
您可以使用这个替代正则表达式:
$parts = explode(" ", $string, 3);

如果所有字段都是相同的格式,那么这个方法就可以奏效。但不幸的是,有些字段不符合这个格式,会给我带来一个不可靠的数据集。使用 preg_match 可以让我使用条件语句,这是非常有优势的。否则,这个方法本来是完美的,谢谢。 - simnom

4
我想我会尝试一下这个。
preg_match('|^([0-9]{2})/([0-9]{2})/([0-9]{4})\s([0-9]{2}):([0-9]{2}):([0-9]{2})\s(.*)$|',$str,$matches);
list($str,$d,$m,$y,$h,$m,$s,$comment)=$matches;

你现在已经拥有了必要的数值,可以按照任何你想要的格式重构时间。

非常感谢!我现在正需要这个 xD。 - leonnicklas

3

我认为,您可以直接使用现有的空格作为分隔符,得到以下表达式:

/([^ ]+) ([^ ]+) (.+)/

那就是:由空格分隔的三组,其中前两组不包含任何空格(但第三组可能会有)。

也许在PHP中不存在这种表示法,但是使用\S+来表示非空白字符会比[^ ]+更好,不是吗? - Kavet Kerek
@stocherilac:我更喜欢精确。\S匹配任何非空白,其中空白可以是空格、制表符或换行符。相比之下,我的表达式仅限于空格字符。根据上下文,\S可能更可取,但我不想猜测确切的上下文。 - Konrad Rudolph
我理解了,只是在确认一下 :) - Kavet Kerek

2

在正则表达式比较耗费资源的情况下。如果这种格式一直被保证存在,你可以通过两个空格进行分割,并使用前两个切片如下:

$str = "10/06/2010 09:10:40 Work not yet started";
$slices = explode(" ", $str, 3);
$timestamp = strtotime($slices[0] . $slices[1]);
echo "String is $str\n";
echo "Timestamp is $timestamp\n";
echo "Timestamp to date is " . strftime("%d.%m.%Y %T", $timestamp) . "\n";

1
在这种情况下,正则表达式是昂贵的 - 你有什么基准来支持这个荒谬的说法吗?正则表达式比大多数人声称/意识到的要快得多,特别是在动态语言中表现得相对较好。最后但并非最不重要的是,这是一种过早的优化。话虽如此,已经提到的“explode”选项是一个非常好的替代方案。 - Konrad Rudolph

1

如果您的日期/时间存储为datetime类型,那么您可以使用类似以下的代码:

preg_match("/^([0-9\\/]{10} [0-9:]{8}) (.*)$/",$str,$matches);
$datetime = $matches[1];
$description = $matches[2];

如果您将日期/时间分开存储,可以使用以下代码:
preg_match("/^([0-9\\/]{10}) ([0-9:]{8}) (.*)$/",$str,$matches);
$date = $matches[1];
$time = $matches[2];
$description = $matches[3];

当然,正则表达式的替代方法是将字符串分割成数组。
list($date,$time,$description) = explode(' ',$str,3);

另一个选项是,假设日期和时间始终具有相同的长度:

$date = substr($str,0,10);
$time = substr($str,11,19);
$description = substr($str,20);

0
if(preg_match('([0-9/]+ [0-9:]+)', $myString, $regs)) {
  $myTime = strtotime($regs[1]);
}

0
如果你只想将它提取为2个字符串,你可以使用以下代码:
([0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4}\s[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2})\s(.*)

0
您可以使用以下代码提取信息:
// sample string you provided
$string = "10/06/2010 09:10:40 Work not yet started";

// regular expression to use
$regex = "/^(\d+)\/(\d+)\/(\d+) (\d+)\:(\d+)\:(\d+) (.+?)$/";

现在,你想要的所有字段都在数组$matches中。 要将信息提取到数组$matches中,可以使用preg_match()函数。

// method 1: just extract
preg_match($regex, $string, $matches);

// method 2: to check if the string matches the format you provided first
//           then do something with the extracted text
if (preg_match($regex, $string, $matches) > 0) {
   // do something
}

为了进一步利用你所获得的信息:

// to get a Unix timestamp out of the matches
// you may use mktime()

// method 1: supposed your date format above is dd/mm/yyyy
$timestamp = mktime($matches[4], $matches[5], $matches[6], 
  $matches[2], $matches[1], $matches[3]);

// method 2: or if your date format above is mm/dd/yyyy
$timestamp = mktime($matches[4], $matches[5], $matches[6], 
  $matches[1], $matches[2], $matches[3]);

然后您可能想要查看时间是否被正确解析:

print date('r', $timestamp)

最后,像这样获取评论:
$comment = $matches[7];

注意时区问题。如果您在生成数据的同一台服务器上解析这些数据,那么您很可能不会有问题。您可能需要从上面的时间戳中添加/减去时间。


0
$s = '10/06/2010 09:10:40 Work not yet started';
$date = substr($s, 0, 19);
$msg = substr($s, 20);

$date = strtotime($date);
// or
$date = strptime($date, "%m/%d/%Y %H:%M:%S");

0

有没有一个简单的正则表达式语法可以匹配这些信息?

是的,有。这是一个“提取”而不是“验证”的练习。你想要在紧随日期时间表达式的空格上仅拆分字符串一次,以形成确切的两个元素。首先匹配日期,然后是空格,然后是时间,然后忘记所有已匹配的内容(`\K`元字符-- 重新启动全字符串匹配),然后匹配用作分隔符的空格。

限制爆炸,以便即使评论中有空格,也只生成两个元素。

代码:(演示)

$string = '10/06/2010 09:10:40 Work not yet started';
var_export(preg_split('/\S+ \S+\K /', $string, 2));

输出:

array (
  0 => '10/06/2010 09:10:40',
  1 => 'Work not yet started',
)

不需要捕获组,并且preg_match()不是很理想,因为它在输出中创建了过多的数据。preg_split()是最直接提供所需输出的单一函数技术。如果这是我的项目,我不会使用其他方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接