PHP获取字符串中的html注释并用<;pre>;标签Regex或DOM


PHP get html comments in string and wrap in <pre> tag. Regex or DOM?

我想在字符串中找到不在<pre>标记中的注释标记,并将它们包装在<pre>标记中。

似乎没有办法使用PHP DOM来"查找"注释。

我已经在使用regex进行一些处理了,但我对regex中的前向和后向非常不熟悉(尚未掌握或真正理解)。

例如,我可能有以下代码;

<!-- Comment 1 -->
<pre>
    <div class="some_html"></div>
    <!-- Comment 2 -->
</pre>

我想将Comment 1包装在<pre>标记中,但显然不包装Comment 2,因为它已经驻留在<pre>中。

在RegEx中通常是如何做到这一点的?

以下是我对消极环视的理解,以及我的尝试,我显然做错了什么!

(?<!<pre>.*?)<!--.*-->(?!.*?</pre>)

如果您计划重新使用此代码,那么您确实应该使用DOM解析器。当使用真实世界的HTML时,每种regex方法都会很快失败。

话虽如此,以下是你可以(但不应该,见上文)做的:

首先,识别评论,例如使用

<!-- (?:(?!-->).)*-->

负先行块可确保.*不会用完注释块。

现在,您需要弄清楚这个注释是否在<pre>块中。这里的关键观察结果是,每个注释后面都有偶数个<pre></pre>元素,而这些元素还没有包含在一个注释中。

因此,请始终以<pre>为一对,遍历文本的其余部分,并检查是否到达末尾。

这看起来像

(?=(?:(?!</?pre>).)*(?:</?pre>(?:(?!</?pre>).)*</?pre>(?:(?!</?pre>).)*)*$)

所以,这就是

<!-- (?:(?!-->).)*-->(?=(?:(?!</?pre>).)*(?:</?pre>(?:(?!</?pre>).)*</?pre>(?:(?!</?pre>).)*)*$)

只写代码的欢呼=)

该表达式的突出构建块是(?:(?!</?pre>).),它匹配不是<pre></pre>序列的起始括号的每个字符。

允许<pre>上的属性和正确的转义留给读者练习。请参阅RegExr中的操作。

似乎没有办法使用PHP DOM来"查找"注释。

你当然可以。。。使用PHP Simple HTML DOM Parser:检查此代码

<?php
$text = '<!-- Comment 1 -->
        <pre>
            <div class="some_html"></div>
            <!-- Comment 2 -->
        </pre>';
echo  "<div>Original Text: <xmp>$text</xmp></div>";
$html = str_get_html($text);
$comments = $html->find('comment');
// if find exists
if ($comments) {
  echo '<br>Find function found '. count($comments) . ' results: ';
  foreach($comments as $key=>$com){
    echo '<br>'.$key . ': ' . $com->tag . ' wich contains = <xmp>' . $com->innertext . '</xmp>';
  }
}
else
  echo "Find() fails !";
?>

$com->innertext会给你类似<!-- Comment 1 -->的评论。。。

你现在只需要随心所欲地清洗它们。例如,使用<!--'s*(.*)'s*-->。。。在这里试试

编辑:

只是一个关于后备的注意事项,它必须有一个固定的宽度,因此你不能使用重复*+或可选项目?

坏消息是,大多数正则表达式风格不允许在lookbacking中只使用任何正则表达式,因为它们不能向后应用正则表达式。因此,正则表达式引擎需要能够计算出在检查查找表之前需要后退多少步。

因此,许多regex风格,包括Perl和Python使用的那些风格,只允许固定长度的字符串。您可以使用任何可以预先确定匹配长度的正则表达式。这意味着您可以使用文字和字符类。不能使用重复项或可选项。可以使用交替,但前提是交替中的所有选项都具有相同的长度。

来源:http://www.regular-expressions.info/lookaround.html

Xpath是您的朋友:

$xpath = new DOMXpath($doc);
foreach($xpath->query('//comment()[not(ancestor::pre)]') as $comment){
  $pre = $doc->createElement("pre");
  $comment->parentNode->insertBefore($pre, $comment);
  $pre->appendChild($comment);
}

这很容易,使用一个称为堆栈计数器的原理,
本质上是计算<pre>标签的数量和</pre>标签的数量,直到您的片段位于HTML代码中
如果<pre></pre>,则表示"<pre>..--you are here--..</pre>"
在这种情况下,只需返回匹配项,未修改-就这么简单。