在preg_match请求中获取所有匹配项

时间:2014-03-14 17:35:19

标签: php regex preg-match

我遇到以下问题,我有这样的结构:

$table = '
<table>
    <tbody>
        <tr valign="top">
            <td>foo</td>
            <td>bar</td>
        </tr>
    </tbody>
</table>
<table>
    <tbody>
        <tr valign="top">
            <td>bee</td>
            <td>dog</td>
        </tr>
    </tbody>
</table>';

我正在尝试检索一个包含所有<tr>的数组,但没有成功。我能做到的最接近的模式,让所有人都搞砸了。

$pattern = "/<tr valign[^>]*>(.*)<\/tr>/s";
preg_match_all($pattern, $table, $matches, PREG_PATTERN_ORDER);

如果我放var_dump($matches),我想要一个返回的数组:

array(
    [0] => "<td>foo</td><td>bar</td>",
    [1] => "<td>bee</td><td>dog</td>"
);

......或接近它的东西。

但我收到了:

string(301) "
    foo
    bar
    "
<table>
        <tbody>
            <tr valign="top">
                <td>bee</td>
                <td>dog</td>
            </tr>
    </tbody></table>

任何人都知道我做错了什么?

提前致谢。

1 个答案:

答案 0 :(得分:7)

你必须使你的量词变得懒惰:.* =&gt; .*?

当您使用贪心量词时,.*将使用所有可能的字符,当您使用延迟量词时,.*?将占用最少的字符数。

当你使用延迟量词时,正则表达式引擎将逐个取字符并测试每个字符的模式完成。

当你使用贪婪量词(默认行为)时,正则表达式引擎将采用所有可能的字符(直到你的情况结束),并逐个字符地回溯,直到模式完成成功。

注意:

添加PREG_PATTERN_ORDER是没用的,因为它是preg_match_all的默认设置。

DOMDocument可能是一个更适合处理html的工具。例如:

$dom = new DOMDocument();
@$dom->loadHTML($table);

$trs = $dom->getElementsByTagName('tr');

$results = array();

foreach ($trs as $tr) {
    if ($tr->hasAttribute('valign')) {
        $children = $tr->childNodes;

        $tmp = '';
        foreach ($children as $child) {
            $tmp .= trim($dom->saveHTML($child));
        }
        if (!empty($tmp)) $results[] = $tmp;
    }
}

echo htmlspecialchars(print_r($results, true));