2

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

似乎没有办法使用 PHP DOM 来“查找”评论。

我已经在使用正则表达式进行一些处理,但是我非常不熟悉(尚未掌握或真正理解)正则表达式的前瞻和后视。

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

<!-- Comment 1 -->

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

我想将评论 1 包装在<pre>标签中,但显然不是评论 2,因为它已经存在于<pre>.

这通常如何在 RegEx 中完成?

这是我对负面环视的理解,以及我的尝试,我显然做错了!

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

4

4 回答 4

2

如果你打算重用这段代码,你真的应该使用 DOM 解析器。当呈现真实世界的 HTML 时,每一种正则表达式方法迟早都会失败。

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

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

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

负前瞻块确保 .* 不会超出注释块。

现在,您需要确定此评论是否在<pre>块内。这里的关键观察是,每条评论后面都有偶数个未包含在其中的要么<pre>或元素。</pre>

因此,请始终以 s 对的形式浏览其余的文本,<pre>并检查您是否到达最后。

这看起来像

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

所以,这将是

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

为只写代码欢呼 =)

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

允许属性<pre>和正确的转义留给读者作为练习。在RegExr中查看此操作。

于 2013-08-16T09:51:46.663 回答
1

似乎没有办法使用 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*-->试试

编辑:

只是关于后视的注释,它必须具有固定宽度,因此您不能使用重复*+项或可选项?

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

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

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

于 2013-08-16T10:01:59.307 回答
0

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);
}
于 2013-08-17T02:00:35.140 回答
0

its quite easy, using a principle called the stack-counter,
essentially you count the amount of <pre> tags and the amount of </pre> tags until the point in the HTML code your segment is placed.
if there are more <pre> than </pre> - this means that "<pre>..--you are here--..</pre>".
in that case, simply return back the match, unmodified - simple as that.

于 2015-01-30T19:43:52.717 回答