只查找多行 C 注释,不查找单行 C 注释

Only find multiline C comment but not single line C comments

假设我有这段文字:

cat file
/* comment */ not a comment /* another comment */

/* delete this  *
/* multiline    *
/* comment      */

/*************
/* and this  *  
/************/
The End

我可以使用带有条件 ? : perl 来仅删除多行注释:

perl -0777 -pE 's/(\/\*(?:\*(?!\/)|[^*])*\*\/)/(=~qr"\R") ? "" : /eg;' file

打印:

/* comment */ not a comment /* another comment */




The End

没有条件:

perl -0777 -pE 's/(\/\*(?:\*(?!\/)|[^*])*\*\/)//g;' file
 not a comment 




The End

有没有办法仅使用正则表达式删除多行 C 样式注释?即,不在替换中使用 perl 条件代码?

您可以使用

perl -0777 -pe 's~/\*(?:(?!\*/|/\*).)*\R(?s).*?\*/~~g' file

模式匹配

  • /\* - /* 字符串
  • (?:(?!\*/|/\*).)* - 除换行符以外的零个或多个字符,每个字符都不是 *//* 字符序列
  • 的起始字符
  • \R - 换行序列
  • (?s) - 现在,. 也将匹配换行符
  • .*? - 尽可能少的任何零个或多个字符
  • \*/ - */ 子串。

参见regex demo

采用SKIP/FAIL方法:

perl -0777 -pe's~/\*\N*?\*/(*SKIP)^|/\*.*?\*/~~gs' file

demo

\N 匹配所有不是换行符的内容
由于使用了 s 标志,点匹配所有字符,包括换行符。

第一个分支匹配“内联”注释,并被迫以 ^ 失败(比写 (*F)(*FAIL) 更短,但结果相同)。 (*SKIP) 回溯控制动词强制不重试先前的位置,因此下一次尝试在结束位置 */ 之后开始。

第二个分支匹配剩余的评论,这些评论必须是多行的。


一个较短的变体,具有相同的两个分支,但这次使用 \K 从匹配结果中排除消耗的字符:

perl -0777 -pe's~/\*\N*?\*/\K|/\*.*?\*/~~gs' file

demo

这次第一个分支成功,但是由于\K之前的所有字符都从匹配结果中移除,所以剩余的空字符串被替换为空字符串。


这两个 search/replace 与更便携的没有太大区别:

s~(/\*.*?\*/)|/\*[\s\S]*?\*/~~g

但工作量较小(不需要捕获组,替换字符串为空)。