2

我的正则表达式很差,这是我的场景,

我正在尝试从包含多个表格的网页中提取一些信息,只有一些表格包含唯一的 url(比如说“very/unique.key”),所以它看起来像这样:

<table ....>
   (bunch of content)
</table>

<table ....>
   (bunch of content)
</table>

<table ....>
   (bunch of content + "very/unique.key" keyword)
</table>

<table ....>
   (bunch of content)
</table>

<table ....>
   (bunch of content + "very/unique.key" keyword)
</table>

所以我想要的是提取所有包含“very/unique.key”关键字的表格内容。这是我尝试过的模式:

$pattern = "#<table[^>]+>((?!\<table)(?=very\/unique\.key).*)<\/table>#i";

这对我没有任何回报......

$pattern = "#<table[^>]+>((?!<table).*)<\/table>#i";

这将返回我从表 1 的打开标签<table...>到最后一个表的关闭标签的所有内容,</table>即使(?!<table)条件...

感谢任何愿意帮助我的人,谢谢。

--编辑--

这是我找到的使用 DOM 循环遍历每个表的解决方案

--我的解决方案--

    $index;//indexes of all the table(s) that contains the keyword
        $cd = 0;//counter

        $DOM = new DOMDocument();
        $DOM->loadHTMLFile("http://uni.corp/sub/sub/target.php?key=123");
        $xpath = new DomXPath($DOM);
        $tables = $DOM->getElementsByTagName("table");
        for ($n = 0; $n < $tables->length; $n++) {
            $rows = $tables->item($n)->getElementsByTagName("tr");
            for ($i = 0; $i < $rows->length; $i++) {
                $cols = $rows->item($i)->getElementsbyTagName("td");
                for ($j = 0; $j < $cols->length; $j++) {


                     $td = $cols->item($j); // grab the td element
                     $img = $xpath->query('./img',$td)->item(0); // grab the first direct img child element


                    if(isset($img) ){
                        $image = $img->getAttribute('src'); // grab the source of the image
                        echo $image;
                        if($image == "very/unique.key"){
                            echo $cols->item($j)->nodeValue, "\t";
                            $index[$cd] = $n;
                            if($n > $cd){
                                $cd++;
                            }


                            echo $cd . " " . $n;//for troubleshooting
                        }


                    }

                }
                echo "<br/>";
            }
        }   

        //loop that echo out only the table(s) that I want which contains the keyword
        $loop = sizeof($index);
        for ($n = 0; $n < $loop; $n++) {
            $temp = $index[$n];
            $rows = $tables->item($temp)->getElementsbyTagName("tr");
            for ($i = 0; $i < $rows->length; $i++) {
                $cols = $rows->item($i)->getElementsbyTagName("td");                
                for ($j = 0; $j < $cols->length; $j++) {
                    echo $cols->item($j)->nodeValue, "\t";
                    //proccess the extracted table content here
                }
                //echo "<br/>";
            }
        }

但就个人而言,我仍然对正则表达式部分感到好奇,希望任何人都可以找到解决这个问题的正则表达式模式。无论如何,感谢所有在这方面帮助/建议我的人(尤其是 AbsoluteƵERØ)。

4

2 回答 2

2

这适用于 PHP5。我们解析表和使用preg_match()来检查密钥。您想要使用这样的方法的原因是因为HTML不必像XML. 因此,您实际上可能没有正确的结束标签。此外,您可能有嵌套表,这会给您尝试使用 REGEX 匹配开始和结束标签的多个结果。这样,我们只检查密钥本身,而不是被解析文档的良好形式。

<?php

$input = "<html>
<table id='1'>
<tr>
<td>This does not contain the key.</td>
</tr>
</table>
<table id='2'>
<tr>
<td>This does contain the unique.key!</td>
</tr>
</table>

<table id='3'>
<tr>
<td>This also contains the unique.key.</td>
</tr>
</table>

</html>";

$html = new DOMDocument;
$html->loadHTML($input);

$findings = array();

$tables = $html->getElementsByTagName('table');
foreach($tables as $table){

    $element = $table->nodeValue;

    if(preg_match('!unique\.key!',$element)){
        $findings[] = $element;
    }
}

print_r($findings);

?>

输出

Array
(
    [0] => This does contain the unique.key!
    [1] => This also contains the unique.key.
)
于 2013-07-26T20:24:14.550 回答
1

虽然我同意你帖子上的评论,但我会给出解决方案。如果您想用其他东西替换very/unique.key,正确的正则表达式看起来像这样

#<table(.*)>((.*)very\/unique\.key(.*))<\/table>#imsU

这里的关键是使用正确的修饰符使其与您的输入字符串一起使用。有关这些修饰符的更多信息,请参阅http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php

现在这是一个示例,我将very/unique.key 替换为“foobar”

<?php
$string = "
<table ....>
   (bunch of content)
</table>

<table ....>
   (bunch of content)
</table>

<table ....>
   bunch of content very/unique.key 
</table>

<table ....>
   (bunch of content)
</table>

<table ....>
   blabla very/unique.key
</table>
";

$pattern = '#<table(.*)>((.*)very\/unique\.key(.*))<\/table>#imsU';

echo preg_replace($pattern, '<table$1>$3foobar$4</table>', $string);
?>

这段代码打印了完全相同的字符串,但两个“very/unique.key”被“foobar”替换,就像我们想要的那样。

虽然这个解决方案可以工作,但它肯定不是最有效也不是最简单的工作。就像 Mehdi 在评论中所说的那样,PHP 有一个专门用于操作 XML(因此是 HTML)的扩展。

这是该扩展程序文档的链接 http://www.php.net/manual/en/intro.dom.php

使用它,您可以轻松浏览每个表元素并找到具有唯一键的元素。

于 2013-07-26T18:44:47.960 回答