使用RegEx(Perl样式)选择未包含在另一个标记中的第一个段落标记

时间:2011-12-13 22:30:38

标签: php regex perl

我有这个html块:

<div>
  <p>First, nested paragraph</p>
</div>
<p>First, non-nested paragraph.</p>
<p>Second paragraph.</p>
<p>Last paragraph.</p>

我正在尝试在该块中选择第一个非嵌套段落。我正在使用PHP的(perl样式)preg_match来查找它,但似乎无法弄清楚如何忽略div中包含的p标记。

这是我到目前为止所做的,但它选择了上面第一段的内容。

/<p>(.+?)<\/p>/is

谢谢!

修改

不幸的是,我没有DOM Parser的奢侈品。

我完全赞赏不使用RegEx来解析HTML的建议,但这并没有真正帮助我的特定用例。我有一个非常受控制的案例,内部应用程序生成结构化文本。我试图替换一些文本,如果它匹配某种模式。这是一个简化的案例,我试图忽略嵌套在其他文本中的文本,HTML是我能想到要解释的最简单的情况。我的实际情况看起来有点像这样(但是更多的数据和缩小):

#[BILLINGCODE|12345|11|15|2001|15|26|50]#
[ITEM1|{{Escaped Description}}|1|1|4031|NONE|15]
#[{{Additional Details }}]#
[ITEM2|{{Escaped Description}}|3|1|7331|NONE|15]
[ITEM3|{{Escaped Description}}|1|1|9431|NONE|15]
[ITEM4|{{Escaped Description}}|1|1|5131|NONE|15]

我必须将某些行的某一列重新格式化为与此类似的大量行。帮助我的第一个问题将有助于实际项目。

5 个答案:

答案 0 :(得分:2)

你的正则表达式不起作用。即使您只有非嵌套段落,您的捕获括号也会匹配First, non-nested ... Last paragraph.

尝试:

<([^>]+)>([^<]*<(?!/?\1)[^<]*)*<\1>

如果\2\1,请抓取p

但HTML解析器可以更好地完成这个imho。

答案 1 :(得分:2)

这样的事情怎么样?

<p>([^<>]+)<\/p>(?=(<[^\/]|$))

预先检查以确保它不在结束标记内;但可以在一个字符串的末尾。可能有更好的方法来查找段落标记中的内容但是你需要避免过于贪婪(a。+?不够)。

答案 2 :(得分:1)

使用两个三步骤。首先,祈祷一切都很好。第二,首先,删除嵌套的所有内容。

s{<div>.*?</div>}{}g;         # HTML example
s/#.*?#//g;                   # 2nd example

然后得到你的结果。剩下的一切现在都没有嵌套。

$result = m{<p>(.*?)</p>};    # HTML example
$result = m{\[(.*?)\]};       # 2nd example

(这是Perl。不知道它在PHP中看起来有多么不同。)

答案 3 :(得分:1)

“您不应该使用正则表达式来解析HTML。”

这是每个人都说的,但没有人真正提供如何实际做到的例子,他们只是鼓吹它。好吧,多亏了Levi Morrison的一些动机,我决定阅读DomDocument并想出如何做到这一点。

对于所有人说“哦,学习解析器太难了,我只会使用正则表达式。”好吧,以前从未对DomDocument或XPath做过任何事情,这花了我10分钟。去阅读DomDocument上的文档并按照你想象的方式解析HTML到。

$myHtml = <<<MARKUP
   <html>
       <head>
            <title>something</title></head>
       <body>
            <div>
                <p>not valid</p>
            </div>
            <p>is valid</p>
            <p>is not valid</p>
            <p>is not valid either</p>
            <div>
                <p>definitely not valid</p>
            </div>
       </body>
   </html>
MARKUP;

$DomDocument = new DOMDocument();
$DomDocument->loadHTML($myHtml);
$DomXPath = new DOMXPath($DomDocument);
$nodeList = $DomXPath->query('body/p');
$yourNode = $DomDocument->saveHtml($nodeList->item(0));

var_dump($yourNode)

// output '<p>is valid</p>'

答案 4 :(得分:0)

您可能希望查看有关使用Regex解析HTML的this post

由于HTML不是常规语言(正则表达式),因此您无法使用Regex删除任意HTML块。使用HTML解析器,它可以比试图破解一些正则表达式更加顺利地完成工作。