正则表达式有助于解析日期

时间:2014-09-22 19:55:37

标签: php regex

我正在尝试从字符串中获取重要日期......

<tr> <td>Account Registered :</td> <td>2008-02-02</td></tr>
<tr> <td>Account Updated :</td> <td>2014-02-01</td></tr>
<tr> <td>Account Expires :</td> <td>2015-02-02</td></tr>

我试过跟随......

preg_match('#<tr> <td>Account Expires :</td> <td>[0-9]{4}-[0-9]{2}-[0-9]{2}#', $result, $matches);

它提供了以下内容......

array (size=1)
  0 => string '<tr> <td>Account Expires :</td> <td>2015-02-02' (length=38)

我想在1个正则表达式或3个不同的正则表达式中获取所有三个日期,请帮助我。感谢

3 个答案:

答案 0 :(得分:3)

您可以使用()设置可在preg_match_all()中访问的捕获组(与全局匹配,与preg_match()不同)。然后你只需要不指定动词Expires

$result = '
<tr> <td>Account Registered :</td> <td>2008-02-02</td></tr>
<tr> <td>Account Updated :</td> <td>2014-02-01</td></tr>
<tr> <td>Account Expires :</td> <td>2015-02-02</td></tr>
';

if(preg_match_all('#<tr>\s*<td>Account\s*([^:]*?)\s*:</td>\s*<td>([0-9]{4}-[0-9]{2}-[0-9]{2})#', $result, $matches, PREG_SET_ORDER)) {
    print_r($matches);

    // Array
    // (
    //     [0] => Array
    //         (
    //             [0] => <tr> <td>Account Registered :</td> <td>2008-02-02
    //             [1] => Registered
    //             [2] => 2008-02-02
    //         )
    // 
    //     [1] => Array
    //         (
    //             [0] => <tr> <td>Account Updated :</td> <td>2014-02-01
    //             [1] => Updated
    //             [2] => 2014-02-01
    //         )
    // 
    //     [2] => Array
    //         (
    //             [0] => <tr> <td>Account Expires :</td> <td>2015-02-02
    //             [1] => Expires
    //             [2] => 2015-02-02
    //         )
    // )
}

But, you shouldn't rely on regex to parse HTML, since HTML isn't a regular language. 此“规则”的一个很好的例外是,如果您的HTML来自您自己的代码,并且您知道可以将其简化为“常规”表达式以进行匹配。 < / p>

答案 1 :(得分:2)

您可以将正则表达式用于这样简单的事情。

preg_match_all('/\b\d{4}-\d{2}-\d{2}\b/', $html, $matches);
print_r($matches[0]);

但我建议使用DOM等解析器来提取这些值。

// Load your HTML
$dom = DOMDocument::loadHTML('
     <tr> <td>foo bar</td> <td>123456789</td></tr>
     <tr> <td>Account Registered :</td> <td>2008-02-02</td></tr>
     <tr> <td>Account Updated :</td> <td>2014-02-01</td></tr>
     <tr> <td>Account Expires :</td> <td>2015-02-02</td></tr>
     <tr> <td>something else</td> <td>foo</td></tr>
');

$xp  = new DOMXPath($dom);
$tag = $xp->query('//tr/td[contains(.,"Account")]/following-sibling::*[1]');

foreach($tag as $t) { 
   echo $t->nodeValue . "\n";
}

// 2008-02-02
// 2014-02-01
// 2015-02-02

如果您不确定前缀的要求,即(Account可能会改变),那么简单的修复就是验证。

$xp  = new DOMXPath($dom);
$tag = $xp->query('//tr/td/following-sibling::*[1]');

foreach($tag as $t) { 
   $date = date_parse($t->nodeValue);
   if ($date["error_count"] == 0 && 
       checkdate($date["month"], $date["day"], $date["year"])) {
         echo $t->nodeValue . "\n";
   }
}

// 2008-02-02
// 2014-02-01
// 2015-02-02

答案 2 :(得分:2)

“解析”HTML的简单正则表达式很好。它可能比使用DOM解析器更快,更具未来性。

这个捕获标签内的所有'日期':

preg_match_all('#>(\d\d\d\d-\d\d-\d\d)<#', $html, $matches);
$dates = $matches[1];
print_r($dates);

使:

Array
(
    [0] => 2008-02-02
    [1] => 2014-02-01
    [2] => 2015-02-02
)

如果$html中有更多日期而你只想要那3个,请忘记这个答案。

如果要在日期(时间)标记中包含时间,请使用以下模式:

#>(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)<#