(php) 正则表达式删除注释但忽略字符串中的出现
Posted
技术标签:
【中文标题】(php) 正则表达式删除注释但忽略字符串中的出现【英文标题】:(php) regexto remove comments but ignore occurances within strings 【发布时间】:2011-01-29 08:56:15 【问题描述】:我正在写一个评论剥离器,并试图在这里满足所有需求。我有下面的代码堆栈,它删除了几乎所有的 cmets,但它实际上走得太远了。很多时间都花在尝试、测试和研究匹配的正则表达式模式上,但我并不认为它们在每个方面都是最好的。
我的问题是我也有“php cmets”(在标准代码甚至 PHP 字符串中并不是真正的 cmets),我实际上并不想删除。
例子:
<?php $Var = "Blah blah //this must not comment"; // this must comment. ?>
最终发生的事情是它虔诚地剥离,这很好,但它留下了某些问题:
<?php $Var = "Blah blah ?>
还有:
也会导致问题,因为注释会删除该行的其余部分,包括结尾?>
看到问题了吗?所以这就是我需要的......
需要忽略 '' 或 "" 中的注释字符 在同一行中使用双斜杠的 PHP 注释应该只删除注释本身,或者应该删除整个 php 代码块。这是我目前使用的模式,请随时告诉我是否可以对现有模式进行改进? :)
$CompressedData = $OriginalData;
$CompressedData = preg_replace('!/\*.*?\*/!s', '', $CompressedData); // removes /* comments */
$CompressedData = preg_replace('!//.*?\n!', '', $CompressedData); // removes //comments
$CompressedData = preg_replace('!#.*?\n!', '', $CompressedData); // removes # comments
$CompressedData = preg_replace('/<!--(.*?)-->/', '', $CompressedData); // removes html comments
您能给我的任何帮助将不胜感激! :)
【问题讨论】:
【参考方案1】:如果要解析 PHP,可以使用token_get_all
获取给定 PHP 代码的 tokens。然后你只需要迭代标记,删除评论标记并将其余部分重新组合在一起。
但是您需要一个单独的 HTML cmets 过程,最好也有一个真正的解析器(如 DOMDocument 提供 DOMDocument::loadHTML
)。
【讨论】:
虽然,大多数“HTML”解析器实际上是 XML 解析器,并且无法正确解析 PHP 常用的 HTML,因为文件本身的格式很少(即使生成的页面是)。 这就是为什么 DOMDocument 有 loadHTML 方法的原因,它可以理解完全混乱的 HTML。 DOMDocument 与查找所有 cmets 并删除它们的 na xpath 表达式组合似乎是 HTML cmets 的有效选项。另外,它使生成的 HTML XHTML 兼容。【参考方案2】:您应该首先仔细考虑您是否真的想要这样做。尽管您正在做的事情可能看起来很简单,但在最坏的情况下,它会变成极其复杂的问题(只需几个正则表达式即可解决)。让我仅举例说明当您尝试从文件中去除 HTML 和 PHP cmets 时会遇到的几个问题。
你不能直接剥离 HTML cmets,因为你可能在 HTML cmets 中有 PHP,比如:
<!-- HTML comment <?php echo 'Actual PHP'; ?> -->
你也不能简单地单独处理 <?php
和 ?>
标签内的东西,因为结尾的 thag ?>
可以在字符串甚至 cmets 内,例如:
<?php /* ?> This is still a PHP comment <?php */ ?>
别忘了,?>
实际上结束了 PHP,如果它前面有一行注释的话。例如:
<?php // ?> This is not a PHP comment <?php ?>
当然,就像您已经说明的那样,字符串中的注释指示符会有很多问题。解析字符串以忽略它们也不是那么简单,因为您必须记住引号可以被转义。喜欢:
<?php
$foo = ' /* // None of these start a comment ';
$bar = ' \' // Remember escaped quotes ';
$orz = " ' \" \' /* // Still not a comment ";
?>
解析顺序也会让你头疼。您不能简单地选择先解析单行 cmets 还是先解析多行 cmets。它们都必须同时解析(即按照它们在文档中出现的顺序)。否则你可能会得到损坏的代码。让我举例说明:
<?php
/* // Multiline comment */
// /* Single Line comment
$omg = 'This is not in a comment */';
?>
如果您首先解析多行 cmets,则第二个 /* 将占用部分字符串,从而破坏代码。如果你先解析单行 cmets,你最终会吃掉第一个 */,这也会破坏代码。
如您所见,如果您打算使用正则表达式解决问题,则必须考虑许多复杂的场景。唯一正确的解决方案是使用某种 PHP 解析器,例如 token_get_all()
,对整个源代码进行标记,去除注释标记并重建文件。恐怕这也不完全简单。它对 HTML cmets 也无济于事,因为 HTML 未被触及。您也不能使用 XML 解析器来获取 HTML cmets,因为 HTML 很少用 PHP 形成良好的格式。
简而言之,您正在做的事情的想法很简单,但实际实现比看起来要困难得多。因此,我建议尽量避免这样做,除非你有充分的理由这样做。
【讨论】:
所有非常好的观点,我已经自动考虑了这些情况并取得了总体成功。正如我在下面的评论中所说,我将其用于内部目的,因此它不必是完美的。我已经设法解决了我的大部分问题,我现在唯一的方法是删除换行符 - 我 DON'T 想要删除字符串中的换行符。看,这通常是针对我自己的编码风格,所以我知道我如何评论事物等,并且我已经相应地使用了 reg-ex。在我所有的测试中,现在一切都很好。 :) 除了“有意的”换行符。【参考方案3】:在 REGEX 中执行此操作的一种方法是使用一个复合表达式和 preg_replace_callback
。
我打算发布一个糟糕的示例,但最好的地方是查看 Dean Edwards 的 JS 打包脚本的 PHP 端口的源代码 - 你应该看到总体思路。
http://joliclic.free.fr/php/javascript-packer/en/
【讨论】:
这只是为了在单个脚本中对 HTML、JS 和 PHP 进行内部压缩,性能不是问题。事实上,它出奇地快,尽管我知道 REGEX 替换本身并不是执行此操作的最佳方式。我已经设法让事情按我的意愿工作,但现在我需要得到它,以便它删除任何 /n 换行符,除非它们包含在“”或“”中。有什么线索吗? Dean 的包装工可能无法帮助我解决这个特定问题。不过这可能很简单……我在这方面有点n00b,呵呵,这主要是我的实验。【参考方案4】:试试这个
private function removeComments( $content )
$content = preg_replace( "!/\*.*?\*/!s" , '', $content );
$content = preg_replace( "/\n\s*\n/" , "\n", $content );
$content = preg_replace( '#^\s*//.+$#m' , "", $content );
$content = preg_replace( '![\s\t]//.*?\n!' , "\n", $content );
$content = preg_replace( '/<\!--.*-->/' , "\n", $content );
return $content;
【讨论】:
以上是关于(php) 正则表达式删除注释但忽略字符串中的出现的主要内容,如果未能解决你的问题,请参考以下文章