将单行注释转换为块注释

6

我需要将单行注释(//...)转换为块注释(/*...*/)。我已经在下面的代码中实现了这个功能,但是我需要让函数跳过任何已经在块注释中的单行注释。目前它匹配任何单行注释,即使单行注释已经在块注释中。

 ## Convert Single Line Comment to Block Comments
 function singleLineComments( &$output ) {
  $output = preg_replace_callback('#//(.*)#m',
   create_function(
     '$match',
     'return "/* " . trim(mb_substr($match[1], 0)) . " */";'
   ), $output
  );
 }
2个回答

3
正如已经提到的,"//..." 可以出现在块注释和字符串字面量中。因此,如果您使用一些正则表达式技巧创建一个小的"解析器",您可以首先匹配其中的任何一种内容(字符串字面量或块注释),然后在此之后测试是否存在 "//..."。
以下是一个小演示:
$code ='A
B
// okay!
/*
C
D
// ignore me E F G
H
*/
I
// yes!
K
L = "foo // bar // string";
done // one more!';

$regex = '@
  ("(?:\\.|[^\r\n\\"])*+")  # group 1: matches double quoted string literals
  |
  (/\*[\s\S]*?\*/)          # group 2: matches multi-line comment blocks
  |
  (//[^\r\n]*+)             # group 3: matches single line comments
@x';

preg_match_all($regex, $code, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);

foreach($matches as $m) {
  if(isset($m[3])) {
    echo "replace the string '{$m[3][0]}' starting at offset: {$m[3][1]}\n";
  }
}

以下是产生的输出结果:
replace the string '// okay!' starting at offset: 6
replace the string '// yes!' starting at offset: 56
replace the string '// one more!' starting at offset: 102

当然,PHP中可能有更多的字符串字面量,但我想你已经明白了我的意思。
希望对你有所帮助。

1
你可以尝试使用负向后瞻:http://www.regular-expressions.info/lookaround.html
## Convert Single Line Comment to Block Comments
function sinlgeLineComments( &$output ) {
  $output = preg_replace_callback('#^((?:(?!/\*).)*?)//(.*)#m',
  create_function(
    '$match',
    'return "/* " . trim(mb_substr($match[1], 0)) . " */";'
  ), $output
 );
}

然而,我担心可能会出现包含//的字符串。例如: $x = "some string // with slashes"; 这将被转换。

如果您的源文件是PHP,则可以使用标记解析器以更精确地解析文件。

http://php.net/manual/en/tokenizer.examples.php

编辑: 忘记了固定长度,可以通过嵌套表达式来克服。上面的代码现在应该可以工作了。我已经用以下代码进行了测试:

$foo = "// this is foo";
sinlgeLineComments($foo);
echo $foo . "\n";

$foo2 = "/* something // this is foo2 */";
sinlgeLineComments($foo2);
echo $foo2 . "\n";

$foo3 = "the quick brown fox";
sinlgeLineComments($foo3);
echo $foo3. "\n";;

我并不担心 $x = "some string // with slashes"; 变成 $x = "some string /* with slashes */";。实际上,这样更好。另一方面,我按照你的建议进行了修改,但是出现了编译错误。警告:preg_replace_callback() [function.preg-replace-callback]:在 C:\wamp\www\LessCSS\Site\cleaner\inc\util.php 的第 29 行,回溯断言长度不固定,编译失败。 - roydukkey
1
PHP的后顾之忧只支持固定长度断言。这意味着您不能编写匹配未定义数量字符的后顾正则表达式,这排除了*和?的使用。更多信息请参见:http://www.php.net/manual/en/regexp.reference.assertions.php - Ahmad Mageed
无法处理这个:/* foo\n// shouldn't match\nbar */ - 您不希望它匹配第二行,但它确实匹配了。 - Alan Moore
@Lance Rushing:我已经成功让代码运行,除了像Alan Moore所说的那样有换行符的字符串。这是一个更新后的函数,看起来你没有更新处理器。<code>## 将单行注释转换为块注释 function sinlgeLineComments( &$output ) { $output = preg_replace_callback('#^((?:(?!/*).)?)//(.)#m', create_function( '$match', 'return "$match[1] /* " . trim(mb_substr($match[2], 0)) . " /";' ), $output ); }</code> 不应该匹配 <code> $output = "/ foo\n// shouldn't match\nbar */\nfoo more//Should Match"</code> - roydukkey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接