如何使用 Perl 从文件中删除多行 C 注释?
Posted
技术标签:
【中文标题】如何使用 Perl 从文件中删除多行 C 注释?【英文标题】:How can I strip multiline C comments from a file using Perl? 【发布时间】:2010-10-27 00:31:45 【问题描述】:谁能用正则表达式让我在一个文件中去除多行 cmets 和单行 cmets?
例如:
" WHOLE "/*...*/" HAS TO BE STRIPED OFF....."
1. /* comment */
2. /* comment1 */ code /* comment2 */ #both /*comment1*/ and /*comment2*/
#has to striped off and rest should
#remain.
3. /*.........
.........
.........
......... */
如果你有这个需要,我真的很感激你....在此先感谢。
【问题讨论】:
根据经验,我发现当您尝试以编程方式操作 C、XML、SQL 等语言时,您应该考虑使用解析器而不是正则表达式。我强烈建议学习解析器生成器、yacc、javacc 等。作为软件开发人员,这对我来说是巨大的回报。 @zimbu668 这是使用解析器非常过分的情况。这里没有嵌套,也没有复杂的结构,只有简单的 cmets 【参考方案1】:这是一个常见问题解答:
perldoc -q comment
发现于perlfaq6:
如何使用正则表达式从文件中去除 C 风格的 cmets?
虽然这实际上是可以做到的,但它比您想象的要难得多。为了 例如,这个单行...
【讨论】:
您可以通过faq.perl.org(始终是最新版本)或 perldoc.perl.org 链接到 perlfaqs。这样,这些网站就可以为搜索答案的人提供良好的谷歌服务。 :)【参考方案2】:还有一个非perl的答案:使用程序stripcmt:
StripCmt 是一个简单的实用程序 在 C 中从 C、C++ 中删除 cmets, 和 Java 源文件。在盛大 Unix 文本处理的传统 程序,它可以作为一个 FIFO(先进先出)过滤器或 接受命令行参数。
【讨论】:
另一个选项就是cpp
。【参考方案3】:
来自perlfaq6“如何使用正则表达式从文件中去除C风格的cmets?”:
虽然这实际上是可以做到的,但它比您想象的要难得多。比如这个单行
perl -0777 -pe 's/\*.*?\*/gs' foo.c
适用于许多但不是所有情况。你看,对于某些类型的 C 程序,特别是那些在引号字符串中看起来是 cmets 的程序来说,这太简单了。为此,您需要这样的东西,由 Jeffrey Friedl 创建,后来由 Fred Curtis 修改。
$/ = undef;
$_ = <>;
s#/\*[^*]*\*+([^/*][^*]*\*+)*/|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#defined $2 ? $2 : ""#gse;
print;
当然,这可以用 /x 修饰符写得更清晰,添加空格和 cmets。此处对其进行了扩展,由 Fred Curtis 提供。
s
/\* ## Start of /* ... */ comment
[^*]*\*+ ## Non-* followed by 1-or-more *'s
(
[^/*][^*]*\*+
)* ## 0-or-more things which don't start with /
## but do end with '*'
/ ## End of /* ... */ comment
| ## OR various things which aren't comments:
(
" ## Start of " ... " string
(
\\. ## Escaped char
| ## OR
[^"\\] ## Non "\
)*
" ## End of " ... " string
| ## OR
' ## Start of ' ... ' string
(
\\. ## Escaped char
| ## OR
[^'\\] ## Non '\
)*
' ## End of ' ... ' string
| ## OR
. ## Anything other char
[^/"'\\]* ## Chars which doesn't start a comment, string or escape
)
defined $2 ? $2 : ""gxse;
稍作修改也删除了 C++ cmets,可能使用连续字符跨越多行:
s#/\*[^*]*\*+([^/*][^*]*\*+)*/|//([^\\]|[^\n][\n]?)*?\n|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^/"'\\]*)#defined $3 ? $3 : ""#gse;
【讨论】:
brian,这个功能几乎可以添加到 perl 中,似乎被问了这么多。至少是国际海事组织。 ...这就是为什么我们有 yacc、flex、bison、ANTLR 等工具的原因。这是你需要一个成熟的解析器而不是正则表达式的东西。 @Paul:这个功能已经在 Perl 中了。 Perl 是一种通用语言。我们不想为出现的每个任务添加内置功能。这就是模块的工作。【参考方案4】:去掉/* */ cmets(包括多行)
s/\/\*.*?\*\///gs
我发布这个是因为它很简单,但是我相信它会在嵌入式 cmets 上绊倒
/* sdafsdfsdf /*sda asd*/ asdsdf */
但由于它们相当少见,我更喜欢简单的正则表达式。
【讨论】:
【参考方案5】:包括测试:
use strict;
use warnings;
use Test::More qw(no_plan);
sub strip_comments
my $string=shift;
$string =~ s#/\*.*?\*/##sg; #strip multiline C comments
return $string;
is(strip_comments('a/* comment1 */ code /* comment2 */b'),'a code b');
is(strip_comments('a/* comment1 /* comment2 */b'),'ab');
is(strip_comments("a/* comment1\n\ncomment */ code /* comment2 */b"),'a code b');
【讨论】:
会弄乱 /* 或 / 出现在字符串中。例如。字符串“This / string”不包含注释开头。 除了不处理字符串中的注释字符(甚至是多字符字符常量)之外,它也不处理反斜杠换行拼接,它允许开始斜杠后跟反斜杠、换行符,然后例如,星号。也不处理 C++ cmets(也可以有反斜杠换行符拼接)。它不处理三元组——唯一相关的是'??/',这意味着反斜杠。这有多重要取决于您的代码需要多么防弹。 mirod 的回答要好得多。 用空字符串替换 cmets 也是错误的。当令牌被意外拼接时,它会改变代码的语义。 C 标准要求在翻译阶段 3 中将 cmets 替换为单个空格字符。【参考方案6】:在 Perl 中,您可以使用 CPAN:Regexp::Common::Comment 应该可以帮助您。我发现使用您描述的 cmets 的一种语言是 Nickle,但也许 php cmets 可以(// 也可以开始单行注释)。
请注意,在任何情况下,使用正则表达式去除注释都是危险的,语言的完整解析器风险要小得多。例如,正则表达式解析器可能会被 print "/*";
之类的东西弄糊涂。
【讨论】:
以上是关于如何使用 Perl 从文件中删除多行 C 注释?的主要内容,如果未能解决你的问题,请参考以下文章