正则表达式是找到一行HTML的正确工具吗?

时间:2009-11-19 03:34:11

标签: php regex html

我有一个PHP脚本可以从服务器中提取一些内容,但问题是内容每天都在变化的行,所以我不能只拉一条特定的行。但是,内容包含在具有唯一ID的div中。是否有可能(也是最好的方法)正则表达式搜索这个唯一的ID,然后将它所在的行传递回我的脚本?

示例:

HTML文件:

<html><head><title>Example</title></head>
<body>
<div id="Alpha"> Blah blah blah </div>
<div id="Beta"> Blah Blah Blah </div>
</body>
</html>

所以我想说我正在寻找一个带有id为alpha的开始div标签的行。代码应返回3,因为第三行是id为alpha的div。

7 个答案:

答案 0 :(得分:3)

根据Jeff Atwood的说法,you should never parse HTML using regex

答案 1 :(得分:3)

冒着为已经越过疯狂山脉的杰夫提供更多选票的风险...... see here

这个论点来回肆虐,但是...这是一个简单的一次性或很少使用的脚本,你正在写,然后肯定使用正则表达式,如果它更复杂,需要可靠,未来很少调整然后我会建议使用HTML解析器。 HTML是一种令人讨厌的非常常见的野兽。使用正确的工具来完成工作...也许在你的情况下它是正则表达式,或者它可能是一个完整的解析器。

答案 2 :(得分:3)

通常,。但是如果你确定div总是一行或里面没有另一个div ,你可以毫无问题地使用它。像/<div id=\"mydivid\">(.*?)</div>/或类似的东西。

否则,DOMDocument将是一种更健全的方式。

编辑从HTML示例中查看。我的回答是“”。 RegEx是一个非常好的工具。

我假设您将HTML作为连续文本而不是行(这将略有不同)。我还假设你想要的行号比行内容更多。

这是一个用于解压缩的PHP代码。 (只是为了提出一些想法)

$HTML =
"<html><head><title>Example</title></head>
<body>
<div id=\"Alpha\"> Blah blah blah </div>
<div id=\"Beta\"> Blah Blah Blah </div>
</body>
</html>";

$ID = "Alpha";

function GetLineOfDIV($HTML, $ID) {
    $RegEx_Alpha = '/\n(<div id="'.$ID.'">.*?<\/div>)\n/m';
    $Index       = preg_match($RegEx_Alpha, $HTML, $Match, PREG_OFFSET_CAPTURE);
    $Match       = $Match[1]; // Only the one in '(...)'
    if ($Match == "")
        return -1;

    //$MatchStr    = $Match[0]; Since you do not want it, so we comment it out.
    $MatchOffset = $Match[1];

    $StartLines = preg_split("/\n/", $HTML, -1, PREG_SPLIT_OFFSET_CAPTURE);
    foreach($StartLines as $I => $StartLine) {
        $LineOffset = $StartLine[1];
        if ($MatchOffset <= $LineOffset)
            return $I + 1;
    }
    return count($StartLines);
}

echo GetLineOfDIV($HTML, $ID);

我希望我能给你一些想法。

答案 3 :(得分:1)

使用专门用于处理(杂乱)HTML的解析器而不是RegEx。如果HTML略有变化,这将使您的应用程序不那么脆弱,并且每次您想要提取新数据时都不必手工制作自定义RegEx。

请参阅此Stack Overflow页面:Mature HTML Parsers for PHP

答案 4 :(得分:1)

涉及唯一ID的事实听起来很有希望,但由于它将是DIV,并且不一定是单行HTML,因此构建正则表达式很困难,并且通常反对解析HTML正则表达式适用。

不推荐。

答案 5 :(得分:1)

由于行号对你来说很重要而不是div的实际内容,所以我倾向于不使用正则表达式。我可能会explode()将字符串放入一个数组中并循环遍历该数组以查找您的标记。像这样:

<?php
$myContent = "[your string of html here]";
$myArray = explode("\n", $myContent);
$arraylen = count($myArray); // So you don't waste time counting the array at every loop
$lineNo = 0;
for($i = 0; $i < $arraylen; $i++)
{
     $pos = strpos($myArray[$i], 'id="Alpha"');
     if($pos !== false)
     {
          $lineNo = $i+1;
          break;
     }
}
?>

免责声明:我没有随时可以使用的php安装进行测试,因此可能需要进行一些调试。

希望这会有所帮助,因为我认为实施解析引擎可能只是为了做一些简单的事情而浪费时间 - 特别是如果它是一次性的。


编辑:如果在此阶段内容对您很重要,那么您可以将其与其他答案结合使用,这些答案可为作业提供足够的正则表达式。


编辑#2:哦,嘿......这是我的两分钱:

"/<div.*?id=\"Alpha\".*?>.*?(<div.*//div>)*.*?//div>/m"

(<div.*//div>)告诉正则表达式引擎它可能会找到嵌套的div标签,如果找到它们只是将它们合并到匹配中,而不是仅停留在第一个</div>。但是,如果只有一个嵌套级别,这只能解决问题。如果有更多,那么正则表达式不适合你抱歉:(。

/m也会使正则表达式引擎忽略换行符,因此您无需在任何地方使用[\S\s]弄脏表达式。

再次,抱歉,我目前没有可以测试此环境的环境,因此您可能需要进行调试。

干杯 伊恩

答案 6 :(得分:0)

@OP因为你的要求很简单,你可以使用字符串方法

$f = fopen("file","r");
if($f){
    $s="";
    while( !feof($f) ){
        $i+=1;
        $line = fgets($f,4096);        
        if (stripos($line,'<div id="Alpha">')!==FALSE){
            print "line number: $i\n";
        }
    }
    fclose($f);
}