【问题标题】:How can I strip multiline C comments from a file using Perl?如何使用 Perl 从文件中删除多行 C 注释?
【发布时间】: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

标签: c perl comments


【解决方案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 "/*"; 之类的东西弄糊涂。

    【讨论】:

      猜你喜欢
      • 2020-08-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-25
      • 2015-02-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多