我的正则表达式很差,这是我的场景,
我试图从一个包含多个表的网页中提取一些信息,只有一些表包含一个唯一的url(比如说"非常/唯一.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/>";
}
}
但就我个人而言,我仍然对Regex部分感到好奇,希望有人能找到这个问题的Regex模式的解决方案。无论如何,感谢所有在这方面帮助/建议我的人(尤其是AbsoluteƵERæ)。
这适用于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.
)
虽然我同意你帖子中的评论,但我会给出解决方案。如果您想用其他东西替换非常/unique.key,正确的正则表达式将类似于以下
#<table(.*)>((.*)very'/unique'.key(.*))<'/table>#imsU
这里的关键是使用正确的修饰符使其与输入字符串一起工作。有关这些修饰符的详细信息,请参见http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php
下面是一个例子,我用"foobar"替换了very/unique.key
<?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);
?>
这段代码打印完全相同的字符串,但用"foobar"替换了两个"very/unique.key",就像我们想要的那样。
尽管这个解决方案可以工作,但它肯定不是最有效也不是最简单的解决方案。正如Mehdi在评论中所说,PHP有一个专门针对XML(即HTML)进行操作的扩展。
这是该扩展的文档链接http://www.php.net/manual/en/intro.dom.php
使用它,您可以轻松地浏览每个表元素,并找到具有唯一键的元素。