【问题标题】:PHP Regex, Matching anything between two specific words/tags with conditionsPHP Regex,将两个特定单词/标签之间的任何内容与条件匹配
【发布时间】:2013-07-27 02:55:18
【问题描述】:

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

我正在尝试从包含多个表格的网页中提取一些信息,只有一些表格包含唯一的 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 = "#&lt;table[^&gt;]+&gt;((?!\&lt;table)(?=very\/unique\.key).*)&lt;\/table&gt;#i";

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

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

这将返回从表 1 的打开标记 &lt;table...&gt; 到最后一个表的结束标记 &lt;/table&gt; 的所有内容,即使使用 (?!&lt;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Ø)。

【问题讨论】:

  • 为什么首先使用正则表达式?怎么样:php.net/manual/en/class.domelement.php
  • 不要使用正则表达式解析 HTML。您无法使用正则表达式可靠地解析 HTML,并且您将面临悲伤和挫败感。一旦 HTML 与您的期望发生变化,您的代码就会被破坏。有关如何使用已经编写、测试和调试的 PHP 模块正确解析 HTML 的示例,请参阅 htmlparsing.com/php
  • 这似乎是XY problem。您真正的问题/问题是如何获取包含上述字符串的表格元素。使用正则表达式只是一种解决方案,此外并没有真正加起来。
  • 我试图解析/提取的网页是一个动态页面,它使用 AJAX/php/JS 生成动态内容。因此,网页中的大多数 html 元素都没有任何唯一标识符,例如 id/class。而且由于内容是动态的,所以我觉得使用 DOM 进行解析可能要困难得多,尽管我的正则表达式也很差。这是一个 Intranet 网页,我用它来解析一定数量的信息,这些信息不应该超过 1 个月(我猜)。感谢您回复我,并感谢任何人都可以使用 DOM 或 Regex 或其他任何方式启发我更多...

标签: php regex html-parsing


【解决方案1】:

这适用于 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.
)

【讨论】:

  • DOM 的新手也是如此,但同时使用它们似乎很好。但是我有 2 个问题,1) 我需要具有唯一键而不是唯一键的整个表格内容,2) 我可以将“uni.corp/sub/sub/target.php?key=123”之类的内容作为 loadHTML() 的输入吗?因为即使我尝试在没有任何条件的情况下循环遍历每个元素,它也会向我返回一个空数组。但无论如何,感谢您为我指明新方向,这很有帮助,再次感谢。
  • 以前犯了一些白痴错误,现在DOM部分工作得很好,只需要弄清楚正则表达式部分,这是行不通的。啊,又是正则表达式,我讨厌正则表达式......无论如何,再次感谢。
  • @user2619841 确切的密钥是什么?你是否正确地逃避它?
  • 正如我上面提到的,它是一个类似“sub/filename.ext”的 url,不知道为什么正则表达式不起作用并且没有返回任何内容,但是感谢您指导我使用 DOM,我找到了获取整个表格内容的解决方案,请检查我的答案,谢谢。
【解决方案2】:

虽然我同意您帖子中的 cmets,但我会给出解决方案。如果你想用其他东西替换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 在 cmets 中所说的那样,PHP 有一个专门用于操作 XML(因此是 HTML)的扩展。

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

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

【讨论】:

  • 感谢您的回复,但不幸的是,它没有给我任何回报:(无论如何,再次感谢您愿意提供帮助
  • 我编辑了我的答案以提供更多细节和更完整的正则表达式:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-14
  • 2017-09-21
  • 1970-01-01
  • 2015-09-05
相关资源
最近更新 更多