如何使用 PHP 从 Javascript 中删除评论
How to strip comments from Javascript using PHP
我想删除这些脚本的评论:
var stName = "MyName"; //I WANT THIS COMMENT TO BE REMOVED
var stLink = "http://domain.com/mydomain";
var stCountry = "United State of America";
使用 PHP 完成此操作的(最佳)方法是什么?
最好的方法是使用实际的解析器或至少自己编写一个词法分析器。
正则表达式的问题在于,如果您考虑所有必须考虑的因素,它会变得非常复杂。
例如,Cagatay Ulubay 推荐的正则表达式 /\/\/[^\n]?/
和 /\/\*(.*)\*\//
会匹配评论,但它们也会匹配更多,比如
var a = '/* the contents of this string will be matches */';
var b = '// and here you will even get a syntax error, because the entire rest of the line is removed';
var c = 'and actually, the regex that matches multiline comments will span across lines, removing everything between the first "/*" and here: */';
/*
this comment, however, will not be matched.
*/
虽然字符串不太可能包含这样的序列,但内联正则表达式确实存在问题:
var regex = /^something.*/; // You see the fake "*/" here?
当前范围很重要,除非从头逐个字符地解析脚本,否则您不可能知道当前范围。
所以你基本上需要构建一个词法分析器。
您需要将代码分成三个不同的部分:
- 普通代码,需要再次输出,注释的开头可能只有一个字符。
- 您丢弃的评论。
- 文字,你也需要输出,但评论不能开始。
现在我能想到的唯一文字是字符串(单引号和双引号)、内联正则表达式和模板字符串(反引号),但这些可能不是全部。
当然,您还必须考虑这些文字中的转义序列,因为您可能会遇到像
这样的内联正则表达式
/^file:\/\/\/*.+/
其中基于单字符的词法分析器只会看到正则表达式 /^file:\/
并错误地将以下 /*.+
解析为多行注释的开头。
因此,在遇到第二个 /
时,您必须回头检查您传递的最后一个字符是否是 \
。字符串的各种引号也是如此。
我会选择 preg_replace()。假设所有注释都是单行注释(// Comment here)你可以这样开始:
$JsCode = 'var stName = "MyName isn\'t \"Foobar\""; //I WANT THIS COMMENT TO BE REMOVED
var stLink = "http://domain.com/mydomain"; // Comment
var stLink2 = \'http://domain.com/mydomain\'; // This comment goes as well
var stCountry = "United State of America"; // Comment here';
$RegEx = '/(["\']((?>[^"\']+)|(?R))*?(?<!\\)["\'])(.*?)\/\/.*$/m';
echo preg_replace($RegEx, '', $JsCode);
输出:
var stName = "MyName isn't \"Foobar\"";
var stLink = "http://domain.com/mydomain";
var stLink2 = 'http://domain.com/mydomain';
var stCountry = "United State of America";
此解决方案远非完美,并且可能对其中包含“//”的字符串有问题。
我想删除这些脚本的评论:
var stName = "MyName"; //I WANT THIS COMMENT TO BE REMOVED
var stLink = "http://domain.com/mydomain";
var stCountry = "United State of America";
使用 PHP 完成此操作的(最佳)方法是什么?
最好的方法是使用实际的解析器或至少自己编写一个词法分析器。
正则表达式的问题在于,如果您考虑所有必须考虑的因素,它会变得非常复杂。
例如,Cagatay Ulubay 推荐的正则表达式 /\/\/[^\n]?/
和 /\/\*(.*)\*\//
会匹配评论,但它们也会匹配更多,比如
var a = '/* the contents of this string will be matches */';
var b = '// and here you will even get a syntax error, because the entire rest of the line is removed';
var c = 'and actually, the regex that matches multiline comments will span across lines, removing everything between the first "/*" and here: */';
/*
this comment, however, will not be matched.
*/
虽然字符串不太可能包含这样的序列,但内联正则表达式确实存在问题:
var regex = /^something.*/; // You see the fake "*/" here?
当前范围很重要,除非从头逐个字符地解析脚本,否则您不可能知道当前范围。
所以你基本上需要构建一个词法分析器。
您需要将代码分成三个不同的部分:
- 普通代码,需要再次输出,注释的开头可能只有一个字符。
- 您丢弃的评论。
- 文字,你也需要输出,但评论不能开始。
现在我能想到的唯一文字是字符串(单引号和双引号)、内联正则表达式和模板字符串(反引号),但这些可能不是全部。
当然,您还必须考虑这些文字中的转义序列,因为您可能会遇到像
/^file:\/\/\/*.+/
其中基于单字符的词法分析器只会看到正则表达式 /^file:\/
并错误地将以下 /*.+
解析为多行注释的开头。
因此,在遇到第二个 /
时,您必须回头检查您传递的最后一个字符是否是 \
。字符串的各种引号也是如此。
我会选择 preg_replace()。假设所有注释都是单行注释(// Comment here)你可以这样开始:
$JsCode = 'var stName = "MyName isn\'t \"Foobar\""; //I WANT THIS COMMENT TO BE REMOVED
var stLink = "http://domain.com/mydomain"; // Comment
var stLink2 = \'http://domain.com/mydomain\'; // This comment goes as well
var stCountry = "United State of America"; // Comment here';
$RegEx = '/(["\']((?>[^"\']+)|(?R))*?(?<!\\)["\'])(.*?)\/\/.*$/m';
echo preg_replace($RegEx, '', $JsCode);
输出:
var stName = "MyName isn't \"Foobar\"";
var stLink = "http://domain.com/mydomain";
var stLink2 = 'http://domain.com/mydomain';
var stCountry = "United State of America";
此解决方案远非完美,并且可能对其中包含“//”的字符串有问题。